Import any XML or CSV File to WordPress - Version 3.3.1

Version Description

  • fixed parsing CSV with empty lines
  • fixed parsing multiple IF statements
  • fixed preview in case when Disable the visual editor when writing is enabled
  • fixed conflict with WooCommerce - Store Exporter Deluxe
  • added notifications for required addons
  • added support for wp all export bundle
  • added support for manual import bundle
  • added feature 'click to download import file'
  • added validation for excerpt and images sections
  • added auto-detect a broken Unique ID notification
  • added import template notifications
  • removed support for importing WooCommerce Orders
  • changed absolute paths to relative in db
Download this release

Release Info

Developer soflyy
Plugin Icon 128x128 Import any XML or CSV File to WordPress
Version 3.3.1
Comparing to
See all releases

Code changes from version 3.3.0 to 3.3.1

Files changed (109) hide show
  1. actions/admin_init.php +7 -3
  2. actions/admin_notices.php +2 -1
  3. actions/wp_ajax_dismiss_notifications.php +16 -0
  4. {libraries → classes}/PHPExcel.php +0 -0
  5. {libraries → classes}/PHPExcel/Autoloader.php +0 -0
  6. {libraries → classes}/PHPExcel/CachedObjectStorage/APC.php +0 -0
  7. {libraries → classes}/PHPExcel/CachedObjectStorage/CacheBase.php +376 -376
  8. {libraries → classes}/PHPExcel/CachedObjectStorage/DiscISAM.php +219 -219
  9. {libraries → classes}/PHPExcel/CachedObjectStorage/ICache.php +0 -0
  10. {libraries → classes}/PHPExcel/CachedObjectStorage/Igbinary.php +152 -152
  11. {libraries → classes}/PHPExcel/CachedObjectStorage/Memcache.php +312 -312
  12. {libraries → classes}/PHPExcel/CachedObjectStorage/Memory.php +125 -125
  13. {libraries → classes}/PHPExcel/CachedObjectStorage/MemoryGZip.php +137 -137
  14. {libraries → classes}/PHPExcel/CachedObjectStorage/MemorySerialized.php +137 -137
  15. {libraries → classes}/PHPExcel/CachedObjectStorage/PHPTemp.php +206 -206
  16. {libraries → classes}/PHPExcel/CachedObjectStorage/SQLite.php +306 -306
  17. {libraries → classes}/PHPExcel/CachedObjectStorage/SQLite3.php +345 -345
  18. {libraries → classes}/PHPExcel/CachedObjectStorage/Wincache.php +294 -294
  19. {libraries → classes}/PHPExcel/CachedObjectStorageFactory.php +0 -0
  20. {libraries → classes}/PHPExcel/CalcEngine/CyclicReferenceStack.php +0 -0
  21. {libraries → classes}/PHPExcel/CalcEngine/Logger.php +0 -0
  22. {libraries → classes}/PHPExcel/Calculation.php +0 -0
  23. {libraries → classes}/PHPExcel/Calculation/Database.php +0 -0
  24. {libraries → classes}/PHPExcel/Calculation/DateTime.php +0 -0
  25. {libraries → classes}/PHPExcel/Calculation/Engineering.php +0 -0
  26. {libraries → classes}/PHPExcel/Calculation/Exception.php +0 -0
  27. {libraries → classes}/PHPExcel/Calculation/ExceptionHandler.php +0 -0
  28. {libraries → classes}/PHPExcel/Calculation/Financial.php +0 -0
  29. {libraries → classes}/PHPExcel/Calculation/FormulaParser.php +0 -0
  30. {libraries → classes}/PHPExcel/Calculation/FormulaToken.php +0 -0
  31. {libraries → classes}/PHPExcel/Calculation/Function.php +0 -0
  32. {libraries → classes}/PHPExcel/Calculation/Functions.php +0 -0
  33. {libraries → classes}/PHPExcel/Calculation/Logical.php +0 -0
  34. {libraries → classes}/PHPExcel/Calculation/LookupRef.php +0 -0
  35. {libraries → classes}/PHPExcel/Calculation/MathTrig.php +0 -0
  36. {libraries → classes}/PHPExcel/Calculation/Statistical.php +0 -0
  37. {libraries → classes}/PHPExcel/Calculation/TextData.php +0 -0
  38. {libraries → classes}/PHPExcel/Calculation/Token/Stack.php +0 -0
  39. {libraries → classes}/PHPExcel/Calculation/functionlist.txt +0 -0
  40. {libraries → classes}/PHPExcel/Cell.php +0 -0
  41. {libraries → classes}/PHPExcel/Cell/AdvancedValueBinder.php +0 -0
  42. {libraries → classes}/PHPExcel/Cell/DataType.php +0 -0
  43. {libraries → classes}/PHPExcel/Cell/DataValidation.php +0 -0
  44. {libraries → classes}/PHPExcel/Cell/DefaultValueBinder.php +0 -0
  45. {libraries → classes}/PHPExcel/Cell/Hyperlink.php +0 -0
  46. {libraries → classes}/PHPExcel/Cell/IValueBinder.php +0 -0
  47. {libraries → classes}/PHPExcel/Comment.php +0 -0
  48. {libraries → classes}/PHPExcel/DocumentProperties.php +0 -0
  49. {libraries → classes}/PHPExcel/DocumentSecurity.php +0 -0
  50. {libraries → classes}/PHPExcel/Exception.php +0 -0
  51. {libraries → classes}/PHPExcel/HashTable.php +0 -0
  52. {libraries → classes}/PHPExcel/IComparable.php +0 -0
  53. {libraries → classes}/PHPExcel/IOFactory.php +0 -0
  54. {libraries → classes}/PHPExcel/NamedRange.php +0 -0
  55. {libraries → classes}/PHPExcel/Reader/Abstract.php +0 -0
  56. {libraries → classes}/PHPExcel/Reader/CSV.php +0 -0
  57. {libraries → classes}/PHPExcel/Reader/DefaultReadFilter.php +0 -0
  58. {libraries → classes}/PHPExcel/Reader/Excel2003XML.php +0 -0
  59. {libraries → classes}/PHPExcel/Reader/Excel2007.php +0 -0
  60. {libraries → classes}/PHPExcel/Reader/Excel2007/Chart.php +0 -0
  61. {libraries → classes}/PHPExcel/Reader/Excel2007/Theme.php +0 -0
  62. {libraries → classes}/PHPExcel/Reader/Excel5.php +7088 -7088
  63. {libraries → classes}/PHPExcel/Reader/Excel5/Escher.php +0 -0
  64. {libraries → classes}/PHPExcel/Reader/Excel5/MD5.php +0 -0
  65. {libraries → classes}/PHPExcel/Reader/Excel5/RC4.php +0 -0
  66. {libraries → classes}/PHPExcel/Reader/Exception.php +0 -0
  67. {libraries → classes}/PHPExcel/Reader/Gnumeric.php +0 -0
  68. {libraries → classes}/PHPExcel/Reader/HTML.php +0 -0
  69. {libraries → classes}/PHPExcel/Reader/IReadFilter.php +0 -0
  70. {libraries → classes}/PHPExcel/Reader/IReader.php +0 -0
  71. {libraries → classes}/PHPExcel/Reader/OOCalc.php +0 -0
  72. {libraries → classes}/PHPExcel/Reader/SYLK.php +0 -0
  73. {libraries → classes}/PHPExcel/ReferenceHelper.php +0 -0
  74. {libraries → classes}/PHPExcel/RichText.php +0 -0
  75. {libraries → classes}/PHPExcel/RichText/ITextElement.php +0 -0
  76. {libraries → classes}/PHPExcel/RichText/Run.php +0 -0
  77. {libraries → classes}/PHPExcel/RichText/TextElement.php +0 -0
  78. {libraries → classes}/PHPExcel/Settings.php +0 -0
  79. {libraries → classes}/PHPExcel/Shared/CodePage.php +0 -0
  80. {libraries → classes}/PHPExcel/Shared/Date.php +0 -0
  81. {libraries → classes}/PHPExcel/Shared/Drawing.php +0 -0
  82. {libraries → classes}/PHPExcel/Shared/Escher.php +0 -0
  83. {libraries → classes}/PHPExcel/Shared/Escher/DgContainer.php +0 -0
  84. {libraries → classes}/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php +0 -0
  85. {libraries → classes}/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php +0 -0
  86. {libraries → classes}/PHPExcel/Shared/Escher/DggContainer.php +0 -0
  87. {libraries → classes}/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php +0 -0
  88. {libraries → classes}/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php +0 -0
  89. {libraries → classes}/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php +0 -0
  90. {libraries → classes}/PHPExcel/Shared/Excel5.php +0 -0
  91. {libraries → classes}/PHPExcel/Shared/File.php +0 -0
  92. {libraries → classes}/PHPExcel/Shared/Font.php +0 -0
  93. {libraries → classes}/PHPExcel/Shared/JAMA/CHANGELOG.TXT +0 -0
  94. {libraries → classes}/PHPExcel/Shared/JAMA/CholeskyDecomposition.php +0 -0
  95. {libraries → classes}/PHPExcel/Shared/JAMA/EigenvalueDecomposition.php +0 -0
  96. {libraries → classes}/PHPExcel/Shared/JAMA/LUDecomposition.php +0 -0
  97. {libraries → classes}/PHPExcel/Shared/JAMA/Matrix.php +0 -0
  98. {libraries → classes}/PHPExcel/Shared/JAMA/QRDecomposition.php +0 -0
  99. {libraries → classes}/PHPExcel/Shared/JAMA/SingularValueDecomposition.php +0 -0
  100. {libraries → classes}/PHPExcel/Shared/JAMA/utils/Error.php +0 -0
  101. {libraries → classes}/PHPExcel/Shared/JAMA/utils/Maths.php +0 -0
  102. {libraries → classes}/PHPExcel/Shared/OLE.php +0 -0
  103. {libraries → classes}/PHPExcel/Shared/OLE/ChainedBlockStream.php +0 -0
  104. {libraries → classes}/PHPExcel/Shared/OLE/PPS.php +0 -0
  105. {libraries → classes}/PHPExcel/Shared/OLE/PPS/File.php +0 -0
  106. {libraries → classes}/PHPExcel/Shared/OLE/PPS/Root.php +0 -0
  107. {libraries → classes}/PHPExcel/Shared/OLERead.php +0 -0
  108. {libraries → classes}/PHPExcel/Shared/PCLZip/gnu-lgpl.txt +504 -504
  109. {libraries → classes}/PHPExcel/Shared/PCLZip/pclzip.lib.php +3060 -5691
actions/admin_init.php CHANGED
@@ -2,9 +2,13 @@
2
 
3
  function pmxi_admin_init(){
4
 
5
- wp_enqueue_script('pmxi-script', WP_ALL_IMPORT_ROOT_URL . '/static/js/wp-all-import.js', array('jquery'), PMXI_VERSION);
6
 
7
  @ini_set('mysql.connect_timeout', 300);
8
- @ini_set('default_socket_timeout', 300);
9
-
 
 
 
 
10
  }
2
 
3
  function pmxi_admin_init(){
4
 
5
+ wp_enqueue_script('wp-all-import-script', WP_ALL_IMPORT_ROOT_URL . '/static/js/wp-all-import.js', array('jquery'), PMXI_VERSION);
6
 
7
  @ini_set('mysql.connect_timeout', 300);
8
+ @ini_set('default_socket_timeout', 300);
9
+
10
+ // if (isset($_GET['addon_notice_ignore']) && '1' == $_GET['addon_notice_ignore'] && isset($_GET['addon_slug']) ) {
11
+ // update_option($_GET['addon_slug'] . '_notice_ignore', 'true');
12
+ // }
13
+
14
  }
actions/admin_notices.php CHANGED
@@ -9,7 +9,7 @@ function pmxi_admin_notices() {
9
  ?>
10
  <div class="error"><p>
11
  <?php printf(
12
- __('<b>%s Plugin</b>: Please update your WP All Import WooCommerce add-on to the latest version</a>', 'pmwi_plugin'),
13
  PMWI_Plugin::getInstance()->getName()
14
  ) ?>
15
  </p></div>
@@ -138,4 +138,5 @@ function pmxi_admin_notices() {
138
  endif;
139
  }
140
  }
 
141
  }
9
  ?>
10
  <div class="error"><p>
11
  <?php printf(
12
+ __('<b>%s Plugin</b>: Please update your WP All Import WooCommerce add-on to the latest version', 'pmwi_plugin'),
13
  PMWI_Plugin::getInstance()->getName()
14
  ) ?>
15
  </p></div>
138
  endif;
139
  }
140
  }
141
+ wp_all_import_addon_notifications();
142
  }
actions/wp_ajax_dismiss_notifications.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function pmxi_wp_ajax_dismiss_notifications(){
3
+
4
+ if ( ! check_ajax_referer( 'wp_all_import_secure', 'security', false )){
5
+ exit( json_encode(array('result' => false, 'msg' => __('Security check', 'wp_all_import_plugin'))) );
6
+ }
7
+
8
+ if ( ! current_user_can('manage_options') ){
9
+ exit( json_encode(array('result' => false, 'msg' => __('Security check', 'wp_all_import_plugin'))) );
10
+ }
11
+
12
+ if (isset($_POST['addon']) ) {
13
+ update_option($_POST['addon'] . '_notice_ignore', 'true');
14
+ }
15
+ exit( json_encode( array('result' => true)));
16
+ }
{libraries → classes}/PHPExcel.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Autoloader.php RENAMED
File without changes
{libraries → classes}/PHPExcel/CachedObjectStorage/APC.php RENAMED
File without changes
{libraries → classes}/PHPExcel/CachedObjectStorage/CacheBase.php RENAMED
@@ -1,376 +1,376 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_CacheBase
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- abstract class PHPExcel_CachedObjectStorage_CacheBase {
37
-
38
- /**
39
- * Parent worksheet
40
- *
41
- * @var PHPExcel_Worksheet
42
- */
43
- protected $_parent;
44
-
45
- /**
46
- * The currently active Cell
47
- *
48
- * @var PHPExcel_Cell
49
- */
50
- protected $_currentObject = null;
51
-
52
- /**
53
- * Coordinate address of the currently active Cell
54
- *
55
- * @var string
56
- */
57
- protected $_currentObjectID = null;
58
-
59
-
60
- /**
61
- * Flag indicating whether the currently active Cell requires saving
62
- *
63
- * @var boolean
64
- */
65
- protected $_currentCellIsDirty = true;
66
-
67
- /**
68
- * An array of cells or cell pointers for the worksheet cells held in this cache,
69
- * and indexed by their coordinate address within the worksheet
70
- *
71
- * @var array of mixed
72
- */
73
- protected $_cellCache = array();
74
-
75
-
76
- /**
77
- * Initialise this new cell collection
78
- *
79
- * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
80
- */
81
- public function __construct(PHPExcel_Worksheet $parent) {
82
- // Set our parent worksheet.
83
- // This is maintained within the cache controller to facilitate re-attaching it to PHPExcel_Cell objects when
84
- // they are woken from a serialized state
85
- $this->_parent = $parent;
86
- } // function __construct()
87
-
88
-
89
- /**
90
- * Return the parent worksheet for this cell collection
91
- *
92
- * @return PHPExcel_Worksheet
93
- */
94
- public function getParent()
95
- {
96
- return $this->_parent;
97
- }
98
-
99
- /**
100
- * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
101
- *
102
- * @param string $pCoord Coordinate address of the cell to check
103
- * @return boolean
104
- */
105
- public function isDataSet($pCoord) {
106
- if ($pCoord === $this->_currentObjectID) {
107
- return true;
108
- }
109
- // Check if the requested entry exists in the cache
110
- return isset($this->_cellCache[$pCoord]);
111
- } // function isDataSet()
112
-
113
-
114
- /**
115
- * Move a cell object from one address to another
116
- *
117
- * @param string $fromAddress Current address of the cell to move
118
- * @param string $toAddress Destination address of the cell to move
119
- * @return boolean
120
- */
121
- public function moveCell($fromAddress, $toAddress) {
122
- if ($fromAddress === $this->_currentObjectID) {
123
- $this->_currentObjectID = $toAddress;
124
- }
125
- $this->_currentCellIsDirty = true;
126
- if (isset($this->_cellCache[$fromAddress])) {
127
- $this->_cellCache[$toAddress] = &$this->_cellCache[$fromAddress];
128
- unset($this->_cellCache[$fromAddress]);
129
- }
130
-
131
- return TRUE;
132
- } // function moveCell()
133
-
134
-
135
- /**
136
- * Add or Update a cell in cache
137
- *
138
- * @param PHPExcel_Cell $cell Cell to update
139
- * @return PHPExcel_Cell
140
- * @throws PHPExcel_Exception
141
- */
142
- public function updateCacheData(PHPExcel_Cell $cell) {
143
- return $this->addCacheData($cell->getCoordinate(),$cell);
144
- } // function updateCacheData()
145
-
146
-
147
- /**
148
- * Delete a cell in cache identified by coordinate address
149
- *
150
- * @param string $pCoord Coordinate address of the cell to delete
151
- * @throws PHPExcel_Exception
152
- */
153
- public function deleteCacheData($pCoord) {
154
- if ($pCoord === $this->_currentObjectID && !is_null($this->_currentObject)) {
155
- $this->_currentObject->detach();
156
- $this->_currentObjectID = $this->_currentObject = null;
157
- }
158
-
159
- if (is_object($this->_cellCache[$pCoord])) {
160
- $this->_cellCache[$pCoord]->detach();
161
- unset($this->_cellCache[$pCoord]);
162
- }
163
- $this->_currentCellIsDirty = false;
164
- } // function deleteCacheData()
165
-
166
-
167
- /**
168
- * Get a list of all cell addresses currently held in cache
169
- *
170
- * @return string[]
171
- */
172
- public function getCellList() {
173
- return array_keys($this->_cellCache);
174
- } // function getCellList()
175
-
176
-
177
- /**
178
- * Sort the list of all cell addresses currently held in cache by row and column
179
- *
180
- * @return string[]
181
- */
182
- public function getSortedCellList() {
183
- $sortKeys = array();
184
- foreach ($this->getCellList() as $coord) {
185
- sscanf($coord,'%[A-Z]%d', $column, $row);
186
- $sortKeys[sprintf('%09d%3s',$row,$column)] = $coord;
187
- }
188
- ksort($sortKeys);
189
-
190
- return array_values($sortKeys);
191
- } // function sortCellList()
192
-
193
-
194
-
195
- /**
196
- * Get highest worksheet column and highest row that have cell records
197
- *
198
- * @return array Highest column name and highest row number
199
- */
200
- public function getHighestRowAndColumn()
201
- {
202
- // Lookup highest column and highest row
203
- $col = array('A' => '1A');
204
- $row = array(1);
205
- foreach ($this->getCellList() as $coord) {
206
- sscanf($coord,'%[A-Z]%d', $c, $r);
207
- $row[$r] = $r;
208
- $col[$c] = strlen($c).$c;
209
- }
210
- if (!empty($row)) {
211
- // Determine highest column and row
212
- $highestRow = max($row);
213
- $highestColumn = substr(max($col),1);
214
- }
215
-
216
- return array( 'row' => $highestRow,
217
- 'column' => $highestColumn
218
- );
219
- }
220
-
221
-
222
- /**
223
- * Return the cell address of the currently active cell object
224
- *
225
- * @return string
226
- */
227
- public function getCurrentAddress()
228
- {
229
- return $this->_currentObjectID;
230
- }
231
-
232
- /**
233
- * Return the column address of the currently active cell object
234
- *
235
- * @return string
236
- */
237
- public function getCurrentColumn()
238
- {
239
- sscanf($this->_currentObjectID, '%[A-Z]%d', $column, $row);
240
- return $column;
241
- }
242
-
243
- /**
244
- * Return the row address of the currently active cell object
245
- *
246
- * @return integer
247
- */
248
- public function getCurrentRow()
249
- {
250
- sscanf($this->_currentObjectID, '%[A-Z]%d', $column, $row);
251
- return (integer) $row;
252
- }
253
-
254
- /**
255
- * Get highest worksheet column
256
- *
257
- * @param string $row Return the highest column for the specified row,
258
- * or the highest column of any row if no row number is passed
259
- * @return string Highest column name
260
- */
261
- public function getHighestColumn($row = null)
262
- {
263
- if ($row == null) {
264
- $colRow = $this->getHighestRowAndColumn();
265
- return $colRow['column'];
266
- }
267
-
268
- $columnList = array(1);
269
- foreach ($this->getCellList() as $coord) {
270
- sscanf($coord,'%[A-Z]%d', $c, $r);
271
- if ($r != $row) {
272
- continue;
273
- }
274
- $columnList[] = PHPExcel_Cell::columnIndexFromString($c);
275
- }
276
- return PHPExcel_Cell::stringFromColumnIndex(max($columnList) - 1);
277
- }
278
-
279
- /**
280
- * Get highest worksheet row
281
- *
282
- * @param string $column Return the highest row for the specified column,
283
- * or the highest row of any column if no column letter is passed
284
- * @return int Highest row number
285
- */
286
- public function getHighestRow($column = null)
287
- {
288
- if ($column == null) {
289
- $colRow = $this->getHighestRowAndColumn();
290
- return $colRow['row'];
291
- }
292
-
293
- $rowList = array(0);
294
- foreach ($this->getCellList() as $coord) {
295
- sscanf($coord,'%[A-Z]%d', $c, $r);
296
- if ($c != $column) {
297
- continue;
298
- }
299
- $rowList[] = $r;
300
- }
301
-
302
- return max($rowList);
303
- }
304
-
305
-
306
- /**
307
- * Generate a unique ID for cache referencing
308
- *
309
- * @return string Unique Reference
310
- */
311
- protected function _getUniqueID() {
312
- if (function_exists('posix_getpid')) {
313
- $baseUnique = posix_getpid();
314
- } else {
315
- $baseUnique = mt_rand();
316
- }
317
- return uniqid($baseUnique,true);
318
- }
319
-
320
- /**
321
- * Clone the cell collection
322
- *
323
- * @param PHPExcel_Worksheet $parent The new worksheet
324
- * @return void
325
- */
326
- public function copyCellCollection(PHPExcel_Worksheet $parent) {
327
- $this->_currentCellIsDirty;
328
- $this->_storeData();
329
-
330
- $this->_parent = $parent;
331
- if (($this->_currentObject !== NULL) && (is_object($this->_currentObject))) {
332
- $this->_currentObject->attach($this);
333
- }
334
- } // function copyCellCollection()
335
-
336
- /**
337
- * Remove a row, deleting all cells in that row
338
- *
339
- * @param string $row Row number to remove
340
- * @return void
341
- */
342
- public function removeRow($row) {
343
- foreach ($this->getCellList() as $coord) {
344
- sscanf($coord,'%[A-Z]%d', $c, $r);
345
- if ($r == $row) {
346
- $this->deleteCacheData($coord);
347
- }
348
- }
349
- }
350
-
351
- /**
352
- * Remove a column, deleting all cells in that column
353
- *
354
- * @param string $column Column ID to remove
355
- * @return void
356
- */
357
- public function removeColumn($column) {
358
- foreach ($this->getCellList() as $coord) {
359
- sscanf($coord,'%[A-Z]%d', $c, $r);
360
- if ($c == $column) {
361
- $this->deleteCacheData($coord);
362
- }
363
- }
364
- }
365
-
366
- /**
367
- * Identify whether the caching method is currently available
368
- * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
369
- *
370
- * @return boolean
371
- */
372
- public static function cacheMethodIsAvailable() {
373
- return true;
374
- }
375
-
376
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_CacheBase
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ abstract class PHPExcel_CachedObjectStorage_CacheBase {
37
+
38
+ /**
39
+ * Parent worksheet
40
+ *
41
+ * @var PHPExcel_Worksheet
42
+ */
43
+ protected $_parent;
44
+
45
+ /**
46
+ * The currently active Cell
47
+ *
48
+ * @var PHPExcel_Cell
49
+ */
50
+ protected $_currentObject = null;
51
+
52
+ /**
53
+ * Coordinate address of the currently active Cell
54
+ *
55
+ * @var string
56
+ */
57
+ protected $_currentObjectID = null;
58
+
59
+
60
+ /**
61
+ * Flag indicating whether the currently active Cell requires saving
62
+ *
63
+ * @var boolean
64
+ */
65
+ protected $_currentCellIsDirty = true;
66
+
67
+ /**
68
+ * An array of cells or cell pointers for the worksheet cells held in this cache,
69
+ * and indexed by their coordinate address within the worksheet
70
+ *
71
+ * @var array of mixed
72
+ */
73
+ protected $_cellCache = array();
74
+
75
+
76
+ /**
77
+ * Initialise this new cell collection
78
+ *
79
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
80
+ */
81
+ public function __construct(PHPExcel_Worksheet $parent) {
82
+ // Set our parent worksheet.
83
+ // This is maintained within the cache controller to facilitate re-attaching it to PHPExcel_Cell objects when
84
+ // they are woken from a serialized state
85
+ $this->_parent = $parent;
86
+ } // function __construct()
87
+
88
+
89
+ /**
90
+ * Return the parent worksheet for this cell collection
91
+ *
92
+ * @return PHPExcel_Worksheet
93
+ */
94
+ public function getParent()
95
+ {
96
+ return $this->_parent;
97
+ }
98
+
99
+ /**
100
+ * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
101
+ *
102
+ * @param string $pCoord Coordinate address of the cell to check
103
+ * @return boolean
104
+ */
105
+ public function isDataSet($pCoord) {
106
+ if ($pCoord === $this->_currentObjectID) {
107
+ return true;
108
+ }
109
+ // Check if the requested entry exists in the cache
110
+ return isset($this->_cellCache[$pCoord]);
111
+ } // function isDataSet()
112
+
113
+
114
+ /**
115
+ * Move a cell object from one address to another
116
+ *
117
+ * @param string $fromAddress Current address of the cell to move
118
+ * @param string $toAddress Destination address of the cell to move
119
+ * @return boolean
120
+ */
121
+ public function moveCell($fromAddress, $toAddress) {
122
+ if ($fromAddress === $this->_currentObjectID) {
123
+ $this->_currentObjectID = $toAddress;
124
+ }
125
+ $this->_currentCellIsDirty = true;
126
+ if (isset($this->_cellCache[$fromAddress])) {
127
+ $this->_cellCache[$toAddress] = &$this->_cellCache[$fromAddress];
128
+ unset($this->_cellCache[$fromAddress]);
129
+ }
130
+
131
+ return TRUE;
132
+ } // function moveCell()
133
+
134
+
135
+ /**
136
+ * Add or Update a cell in cache
137
+ *
138
+ * @param PHPExcel_Cell $cell Cell to update
139
+ * @return PHPExcel_Cell
140
+ * @throws PHPExcel_Exception
141
+ */
142
+ public function updateCacheData(PHPExcel_Cell $cell) {
143
+ return $this->addCacheData($cell->getCoordinate(),$cell);
144
+ } // function updateCacheData()
145
+
146
+
147
+ /**
148
+ * Delete a cell in cache identified by coordinate address
149
+ *
150
+ * @param string $pCoord Coordinate address of the cell to delete
151
+ * @throws PHPExcel_Exception
152
+ */
153
+ public function deleteCacheData($pCoord) {
154
+ if ($pCoord === $this->_currentObjectID && !is_null($this->_currentObject)) {
155
+ $this->_currentObject->detach();
156
+ $this->_currentObjectID = $this->_currentObject = null;
157
+ }
158
+
159
+ if (is_object($this->_cellCache[$pCoord])) {
160
+ $this->_cellCache[$pCoord]->detach();
161
+ unset($this->_cellCache[$pCoord]);
162
+ }
163
+ $this->_currentCellIsDirty = false;
164
+ } // function deleteCacheData()
165
+
166
+
167
+ /**
168
+ * Get a list of all cell addresses currently held in cache
169
+ *
170
+ * @return string[]
171
+ */
172
+ public function getCellList() {
173
+ return array_keys($this->_cellCache);
174
+ } // function getCellList()
175
+
176
+
177
+ /**
178
+ * Sort the list of all cell addresses currently held in cache by row and column
179
+ *
180
+ * @return string[]
181
+ */
182
+ public function getSortedCellList() {
183
+ $sortKeys = array();
184
+ foreach ($this->getCellList() as $coord) {
185
+ sscanf($coord,'%[A-Z]%d', $column, $row);
186
+ $sortKeys[sprintf('%09d%3s',$row,$column)] = $coord;
187
+ }
188
+ ksort($sortKeys);
189
+
190
+ return array_values($sortKeys);
191
+ } // function sortCellList()
192
+
193
+
194
+
195
+ /**
196
+ * Get highest worksheet column and highest row that have cell records
197
+ *
198
+ * @return array Highest column name and highest row number
199
+ */
200
+ public function getHighestRowAndColumn()
201
+ {
202
+ // Lookup highest column and highest row
203
+ $col = array('A' => '1A');
204
+ $row = array(1);
205
+ foreach ($this->getCellList() as $coord) {
206
+ sscanf($coord,'%[A-Z]%d', $c, $r);
207
+ $row[$r] = $r;
208
+ $col[$c] = strlen($c).$c;
209
+ }
210
+ if (!empty($row)) {
211
+ // Determine highest column and row
212
+ $highestRow = max($row);
213
+ $highestColumn = substr(max($col),1);
214
+ }
215
+
216
+ return array( 'row' => $highestRow,
217
+ 'column' => $highestColumn
218
+ );
219
+ }
220
+
221
+
222
+ /**
223
+ * Return the cell address of the currently active cell object
224
+ *
225
+ * @return string
226
+ */
227
+ public function getCurrentAddress()
228
+ {
229
+ return $this->_currentObjectID;
230
+ }
231
+
232
+ /**
233
+ * Return the column address of the currently active cell object
234
+ *
235
+ * @return string
236
+ */
237
+ public function getCurrentColumn()
238
+ {
239
+ sscanf($this->_currentObjectID, '%[A-Z]%d', $column, $row);
240
+ return $column;
241
+ }
242
+
243
+ /**
244
+ * Return the row address of the currently active cell object
245
+ *
246
+ * @return integer
247
+ */
248
+ public function getCurrentRow()
249
+ {
250
+ sscanf($this->_currentObjectID, '%[A-Z]%d', $column, $row);
251
+ return (integer) $row;
252
+ }
253
+
254
+ /**
255
+ * Get highest worksheet column
256
+ *
257
+ * @param string $row Return the highest column for the specified row,
258
+ * or the highest column of any row if no row number is passed
259
+ * @return string Highest column name
260
+ */
261
+ public function getHighestColumn($row = null)
262
+ {
263
+ if ($row == null) {
264
+ $colRow = $this->getHighestRowAndColumn();
265
+ return $colRow['column'];
266
+ }
267
+
268
+ $columnList = array(1);
269
+ foreach ($this->getCellList() as $coord) {
270
+ sscanf($coord,'%[A-Z]%d', $c, $r);
271
+ if ($r != $row) {
272
+ continue;
273
+ }
274
+ $columnList[] = PHPExcel_Cell::columnIndexFromString($c);
275
+ }
276
+ return PHPExcel_Cell::stringFromColumnIndex(max($columnList) - 1);
277
+ }
278
+
279
+ /**
280
+ * Get highest worksheet row
281
+ *
282
+ * @param string $column Return the highest row for the specified column,
283
+ * or the highest row of any column if no column letter is passed
284
+ * @return int Highest row number
285
+ */
286
+ public function getHighestRow($column = null)
287
+ {
288
+ if ($column == null) {
289
+ $colRow = $this->getHighestRowAndColumn();
290
+ return $colRow['row'];
291
+ }
292
+
293
+ $rowList = array(0);
294
+ foreach ($this->getCellList() as $coord) {
295
+ sscanf($coord,'%[A-Z]%d', $c, $r);
296
+ if ($c != $column) {
297
+ continue;
298
+ }
299
+ $rowList[] = $r;
300
+ }
301
+
302
+ return max($rowList);
303
+ }
304
+
305
+
306
+ /**
307
+ * Generate a unique ID for cache referencing
308
+ *
309
+ * @return string Unique Reference
310
+ */
311
+ protected function _getUniqueID() {
312
+ if (function_exists('posix_getpid')) {
313
+ $baseUnique = posix_getpid();
314
+ } else {
315
+ $baseUnique = mt_rand();
316
+ }
317
+ return uniqid($baseUnique,true);
318
+ }
319
+
320
+ /**
321
+ * Clone the cell collection
322
+ *
323
+ * @param PHPExcel_Worksheet $parent The new worksheet
324
+ * @return void
325
+ */
326
+ public function copyCellCollection(PHPExcel_Worksheet $parent) {
327
+ $this->_currentCellIsDirty;
328
+ $this->_storeData();
329
+
330
+ $this->_parent = $parent;
331
+ if (($this->_currentObject !== NULL) && (is_object($this->_currentObject))) {
332
+ $this->_currentObject->attach($this);
333
+ }
334
+ } // function copyCellCollection()
335
+
336
+ /**
337
+ * Remove a row, deleting all cells in that row
338
+ *
339
+ * @param string $row Row number to remove
340
+ * @return void
341
+ */
342
+ public function removeRow($row) {
343
+ foreach ($this->getCellList() as $coord) {
344
+ sscanf($coord,'%[A-Z]%d', $c, $r);
345
+ if ($r == $row) {
346
+ $this->deleteCacheData($coord);
347
+ }
348
+ }
349
+ }
350
+
351
+ /**
352
+ * Remove a column, deleting all cells in that column
353
+ *
354
+ * @param string $column Column ID to remove
355
+ * @return void
356
+ */
357
+ public function removeColumn($column) {
358
+ foreach ($this->getCellList() as $coord) {
359
+ sscanf($coord,'%[A-Z]%d', $c, $r);
360
+ if ($c == $column) {
361
+ $this->deleteCacheData($coord);
362
+ }
363
+ }
364
+ }
365
+
366
+ /**
367
+ * Identify whether the caching method is currently available
368
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
369
+ *
370
+ * @return boolean
371
+ */
372
+ public static function cacheMethodIsAvailable() {
373
+ return true;
374
+ }
375
+
376
+ }
{libraries → classes}/PHPExcel/CachedObjectStorage/DiscISAM.php RENAMED
@@ -1,219 +1,219 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_DiscISAM
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- class PHPExcel_CachedObjectStorage_DiscISAM extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
-
38
- /**
39
- * Name of the file for this cache
40
- *
41
- * @var string
42
- */
43
- private $_fileName = NULL;
44
-
45
- /**
46
- * File handle for this cache file
47
- *
48
- * @var resource
49
- */
50
- private $_fileHandle = NULL;
51
-
52
- /**
53
- * Directory/Folder where the cache file is located
54
- *
55
- * @var string
56
- */
57
- private $_cacheDirectory = NULL;
58
-
59
-
60
- /**
61
- * Store cell data in cache for the current cell object if it's "dirty",
62
- * and the 'nullify' the current cell object
63
- *
64
- * @return void
65
- * @throws PHPExcel_Exception
66
- */
67
- protected function _storeData() {
68
- if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
69
- $this->_currentObject->detach();
70
-
71
- fseek($this->_fileHandle,0,SEEK_END);
72
-
73
- $this->_cellCache[$this->_currentObjectID] = array(
74
- 'ptr' => ftell($this->_fileHandle),
75
- 'sz' => fwrite($this->_fileHandle, serialize($this->_currentObject))
76
- );
77
- $this->_currentCellIsDirty = false;
78
- }
79
- $this->_currentObjectID = $this->_currentObject = null;
80
- } // function _storeData()
81
-
82
-
83
- /**
84
- * Add or Update a cell in cache identified by coordinate address
85
- *
86
- * @param string $pCoord Coordinate address of the cell to update
87
- * @param PHPExcel_Cell $cell Cell to update
88
- * @return PHPExcel_Cell
89
- * @throws PHPExcel_Exception
90
- */
91
- public function addCacheData($pCoord, PHPExcel_Cell $cell) {
92
- if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
93
- $this->_storeData();
94
- }
95
-
96
- $this->_currentObjectID = $pCoord;
97
- $this->_currentObject = $cell;
98
- $this->_currentCellIsDirty = true;
99
-
100
- return $cell;
101
- } // function addCacheData()
102
-
103
-
104
- /**
105
- * Get cell at a specific coordinate
106
- *
107
- * @param string $pCoord Coordinate of the cell
108
- * @throws PHPExcel_Exception
109
- * @return PHPExcel_Cell Cell that was found, or null if not found
110
- */
111
- public function getCacheData($pCoord) {
112
- if ($pCoord === $this->_currentObjectID) {
113
- return $this->_currentObject;
114
- }
115
- $this->_storeData();
116
-
117
- // Check if the entry that has been requested actually exists
118
- if (!isset($this->_cellCache[$pCoord])) {
119
- // Return null if requested entry doesn't exist in cache
120
- return null;
121
- }
122
-
123
- // Set current entry to the requested entry
124
- $this->_currentObjectID = $pCoord;
125
- fseek($this->_fileHandle, $this->_cellCache[$pCoord]['ptr']);
126
- $this->_currentObject = unserialize(fread($this->_fileHandle, $this->_cellCache[$pCoord]['sz']));
127
- // Re-attach this as the cell's parent
128
- $this->_currentObject->attach($this);
129
-
130
- // Return requested entry
131
- return $this->_currentObject;
132
- } // function getCacheData()
133
-
134
-
135
- /**
136
- * Get a list of all cell addresses currently held in cache
137
- *
138
- * @return string[]
139
- */
140
- public function getCellList() {
141
- if ($this->_currentObjectID !== null) {
142
- $this->_storeData();
143
- }
144
-
145
- return parent::getCellList();
146
- }
147
-
148
-
149
- /**
150
- * Clone the cell collection
151
- *
152
- * @param PHPExcel_Worksheet $parent The new worksheet
153
- * @return void
154
- */
155
- public function copyCellCollection(PHPExcel_Worksheet $parent) {
156
- parent::copyCellCollection($parent);
157
- // Get a new id for the new file name
158
- $baseUnique = $this->_getUniqueID();
159
- $newFileName = $this->_cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache';
160
- // Copy the existing cell cache file
161
- copy ($this->_fileName,$newFileName);
162
- $this->_fileName = $newFileName;
163
- // Open the copied cell cache file
164
- $this->_fileHandle = fopen($this->_fileName,'a+');
165
- } // function copyCellCollection()
166
-
167
-
168
- /**
169
- * Clear the cell collection and disconnect from our parent
170
- *
171
- * @return void
172
- */
173
- public function unsetWorksheetCells() {
174
- if(!is_null($this->_currentObject)) {
175
- $this->_currentObject->detach();
176
- $this->_currentObject = $this->_currentObjectID = null;
177
- }
178
- $this->_cellCache = array();
179
-
180
- // detach ourself from the worksheet, so that it can then delete this object successfully
181
- $this->_parent = null;
182
-
183
- // Close down the temporary cache file
184
- $this->__destruct();
185
- } // function unsetWorksheetCells()
186
-
187
-
188
- /**
189
- * Initialise this new cell collection
190
- *
191
- * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
192
- * @param array of mixed $arguments Additional initialisation arguments
193
- */
194
- public function __construct(PHPExcel_Worksheet $parent, $arguments) {
195
- $this->_cacheDirectory = ((isset($arguments['dir'])) && ($arguments['dir'] !== NULL))
196
- ? $arguments['dir']
197
- : PHPExcel_Shared_File::sys_get_temp_dir();
198
-
199
- parent::__construct($parent);
200
- if (is_null($this->_fileHandle)) {
201
- $baseUnique = $this->_getUniqueID();
202
- $this->_fileName = $this->_cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache';
203
- $this->_fileHandle = fopen($this->_fileName,'a+');
204
- }
205
- } // function __construct()
206
-
207
-
208
- /**
209
- * Destroy this cell collection
210
- */
211
- public function __destruct() {
212
- if (!is_null($this->_fileHandle)) {
213
- fclose($this->_fileHandle);
214
- unlink($this->_fileName);
215
- }
216
- $this->_fileHandle = null;
217
- } // function __destruct()
218
-
219
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_DiscISAM
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ class PHPExcel_CachedObjectStorage_DiscISAM extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
+
38
+ /**
39
+ * Name of the file for this cache
40
+ *
41
+ * @var string
42
+ */
43
+ private $_fileName = NULL;
44
+
45
+ /**
46
+ * File handle for this cache file
47
+ *
48
+ * @var resource
49
+ */
50
+ private $_fileHandle = NULL;
51
+
52
+ /**
53
+ * Directory/Folder where the cache file is located
54
+ *
55
+ * @var string
56
+ */
57
+ private $_cacheDirectory = NULL;
58
+
59
+
60
+ /**
61
+ * Store cell data in cache for the current cell object if it's "dirty",
62
+ * and the 'nullify' the current cell object
63
+ *
64
+ * @return void
65
+ * @throws PHPExcel_Exception
66
+ */
67
+ protected function _storeData() {
68
+ if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
69
+ $this->_currentObject->detach();
70
+
71
+ fseek($this->_fileHandle,0,SEEK_END);
72
+
73
+ $this->_cellCache[$this->_currentObjectID] = array(
74
+ 'ptr' => ftell($this->_fileHandle),
75
+ 'sz' => fwrite($this->_fileHandle, serialize($this->_currentObject))
76
+ );
77
+ $this->_currentCellIsDirty = false;
78
+ }
79
+ $this->_currentObjectID = $this->_currentObject = null;
80
+ } // function _storeData()
81
+
82
+
83
+ /**
84
+ * Add or Update a cell in cache identified by coordinate address
85
+ *
86
+ * @param string $pCoord Coordinate address of the cell to update
87
+ * @param PHPExcel_Cell $cell Cell to update
88
+ * @return PHPExcel_Cell
89
+ * @throws PHPExcel_Exception
90
+ */
91
+ public function addCacheData($pCoord, PHPExcel_Cell $cell) {
92
+ if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
93
+ $this->_storeData();
94
+ }
95
+
96
+ $this->_currentObjectID = $pCoord;
97
+ $this->_currentObject = $cell;
98
+ $this->_currentCellIsDirty = true;
99
+
100
+ return $cell;
101
+ } // function addCacheData()
102
+
103
+
104
+ /**
105
+ * Get cell at a specific coordinate
106
+ *
107
+ * @param string $pCoord Coordinate of the cell
108
+ * @throws PHPExcel_Exception
109
+ * @return PHPExcel_Cell Cell that was found, or null if not found
110
+ */
111
+ public function getCacheData($pCoord) {
112
+ if ($pCoord === $this->_currentObjectID) {
113
+ return $this->_currentObject;
114
+ }
115
+ $this->_storeData();
116
+
117
+ // Check if the entry that has been requested actually exists
118
+ if (!isset($this->_cellCache[$pCoord])) {
119
+ // Return null if requested entry doesn't exist in cache
120
+ return null;
121
+ }
122
+
123
+ // Set current entry to the requested entry
124
+ $this->_currentObjectID = $pCoord;
125
+ fseek($this->_fileHandle, $this->_cellCache[$pCoord]['ptr']);
126
+ $this->_currentObject = unserialize(fread($this->_fileHandle, $this->_cellCache[$pCoord]['sz']));
127
+ // Re-attach this as the cell's parent
128
+ $this->_currentObject->attach($this);
129
+
130
+ // Return requested entry
131
+ return $this->_currentObject;
132
+ } // function getCacheData()
133
+
134
+
135
+ /**
136
+ * Get a list of all cell addresses currently held in cache
137
+ *
138
+ * @return string[]
139
+ */
140
+ public function getCellList() {
141
+ if ($this->_currentObjectID !== null) {
142
+ $this->_storeData();
143
+ }
144
+
145
+ return parent::getCellList();
146
+ }
147
+
148
+
149
+ /**
150
+ * Clone the cell collection
151
+ *
152
+ * @param PHPExcel_Worksheet $parent The new worksheet
153
+ * @return void
154
+ */
155
+ public function copyCellCollection(PHPExcel_Worksheet $parent) {
156
+ parent::copyCellCollection($parent);
157
+ // Get a new id for the new file name
158
+ $baseUnique = $this->_getUniqueID();
159
+ $newFileName = $this->_cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache';
160
+ // Copy the existing cell cache file
161
+ copy ($this->_fileName,$newFileName);
162
+ $this->_fileName = $newFileName;
163
+ // Open the copied cell cache file
164
+ $this->_fileHandle = fopen($this->_fileName,'a+');
165
+ } // function copyCellCollection()
166
+
167
+
168
+ /**
169
+ * Clear the cell collection and disconnect from our parent
170
+ *
171
+ * @return void
172
+ */
173
+ public function unsetWorksheetCells() {
174
+ if(!is_null($this->_currentObject)) {
175
+ $this->_currentObject->detach();
176
+ $this->_currentObject = $this->_currentObjectID = null;
177
+ }
178
+ $this->_cellCache = array();
179
+
180
+ // detach ourself from the worksheet, so that it can then delete this object successfully
181
+ $this->_parent = null;
182
+
183
+ // Close down the temporary cache file
184
+ $this->__destruct();
185
+ } // function unsetWorksheetCells()
186
+
187
+
188
+ /**
189
+ * Initialise this new cell collection
190
+ *
191
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
192
+ * @param array of mixed $arguments Additional initialisation arguments
193
+ */
194
+ public function __construct(PHPExcel_Worksheet $parent, $arguments) {
195
+ $this->_cacheDirectory = ((isset($arguments['dir'])) && ($arguments['dir'] !== NULL))
196
+ ? $arguments['dir']
197
+ : PHPExcel_Shared_File::sys_get_temp_dir();
198
+
199
+ parent::__construct($parent);
200
+ if (is_null($this->_fileHandle)) {
201
+ $baseUnique = $this->_getUniqueID();
202
+ $this->_fileName = $this->_cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache';
203
+ $this->_fileHandle = fopen($this->_fileName,'a+');
204
+ }
205
+ } // function __construct()
206
+
207
+
208
+ /**
209
+ * Destroy this cell collection
210
+ */
211
+ public function __destruct() {
212
+ if (!is_null($this->_fileHandle)) {
213
+ fclose($this->_fileHandle);
214
+ unlink($this->_fileName);
215
+ }
216
+ $this->_fileHandle = null;
217
+ } // function __destruct()
218
+
219
+ }
{libraries → classes}/PHPExcel/CachedObjectStorage/ICache.php RENAMED
File without changes
{libraries → classes}/PHPExcel/CachedObjectStorage/Igbinary.php RENAMED
@@ -1,152 +1,152 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_Igbinary
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- class PHPExcel_CachedObjectStorage_Igbinary extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
-
38
- /**
39
- * Store cell data in cache for the current cell object if it's "dirty",
40
- * and the 'nullify' the current cell object
41
- *
42
- * @return void
43
- * @throws PHPExcel_Exception
44
- */
45
- protected function _storeData() {
46
- if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
47
- $this->_currentObject->detach();
48
-
49
- $this->_cellCache[$this->_currentObjectID] = igbinary_serialize($this->_currentObject);
50
- $this->_currentCellIsDirty = false;
51
- }
52
- $this->_currentObjectID = $this->_currentObject = null;
53
- } // function _storeData()
54
-
55
-
56
- /**
57
- * Add or Update a cell in cache identified by coordinate address
58
- *
59
- * @param string $pCoord Coordinate address of the cell to update
60
- * @param PHPExcel_Cell $cell Cell to update
61
- * @return PHPExcel_Cell
62
- * @throws PHPExcel_Exception
63
- */
64
- public function addCacheData($pCoord, PHPExcel_Cell $cell) {
65
- if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
66
- $this->_storeData();
67
- }
68
-
69
- $this->_currentObjectID = $pCoord;
70
- $this->_currentObject = $cell;
71
- $this->_currentCellIsDirty = true;
72
-
73
- return $cell;
74
- } // function addCacheData()
75
-
76
-
77
- /**
78
- * Get cell at a specific coordinate
79
- *
80
- * @param string $pCoord Coordinate of the cell
81
- * @throws PHPExcel_Exception
82
- * @return PHPExcel_Cell Cell that was found, or null if not found
83
- */
84
- public function getCacheData($pCoord) {
85
- if ($pCoord === $this->_currentObjectID) {
86
- return $this->_currentObject;
87
- }
88
- $this->_storeData();
89
-
90
- // Check if the entry that has been requested actually exists
91
- if (!isset($this->_cellCache[$pCoord])) {
92
- // Return null if requested entry doesn't exist in cache
93
- return null;
94
- }
95
-
96
- // Set current entry to the requested entry
97
- $this->_currentObjectID = $pCoord;
98
- $this->_currentObject = igbinary_unserialize($this->_cellCache[$pCoord]);
99
- // Re-attach this as the cell's parent
100
- $this->_currentObject->attach($this);
101
-
102
- // Return requested entry
103
- return $this->_currentObject;
104
- } // function getCacheData()
105
-
106
-
107
- /**
108
- * Get a list of all cell addresses currently held in cache
109
- *
110
- * @return string[]
111
- */
112
- public function getCellList() {
113
- if ($this->_currentObjectID !== null) {
114
- $this->_storeData();
115
- }
116
-
117
- return parent::getCellList();
118
- }
119
-
120
-
121
- /**
122
- * Clear the cell collection and disconnect from our parent
123
- *
124
- * @return void
125
- */
126
- public function unsetWorksheetCells() {
127
- if(!is_null($this->_currentObject)) {
128
- $this->_currentObject->detach();
129
- $this->_currentObject = $this->_currentObjectID = null;
130
- }
131
- $this->_cellCache = array();
132
-
133
- // detach ourself from the worksheet, so that it can then delete this object successfully
134
- $this->_parent = null;
135
- } // function unsetWorksheetCells()
136
-
137
-
138
- /**
139
- * Identify whether the caching method is currently available
140
- * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
141
- *
142
- * @return boolean
143
- */
144
- public static function cacheMethodIsAvailable() {
145
- if (!function_exists('igbinary_serialize')) {
146
- return false;
147
- }
148
-
149
- return true;
150
- }
151
-
152
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_Igbinary
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ class PHPExcel_CachedObjectStorage_Igbinary extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
+
38
+ /**
39
+ * Store cell data in cache for the current cell object if it's "dirty",
40
+ * and the 'nullify' the current cell object
41
+ *
42
+ * @return void
43
+ * @throws PHPExcel_Exception
44
+ */
45
+ protected function _storeData() {
46
+ if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
47
+ $this->_currentObject->detach();
48
+
49
+ $this->_cellCache[$this->_currentObjectID] = igbinary_serialize($this->_currentObject);
50
+ $this->_currentCellIsDirty = false;
51
+ }
52
+ $this->_currentObjectID = $this->_currentObject = null;
53
+ } // function _storeData()
54
+
55
+
56
+ /**
57
+ * Add or Update a cell in cache identified by coordinate address
58
+ *
59
+ * @param string $pCoord Coordinate address of the cell to update
60
+ * @param PHPExcel_Cell $cell Cell to update
61
+ * @return PHPExcel_Cell
62
+ * @throws PHPExcel_Exception
63
+ */
64
+ public function addCacheData($pCoord, PHPExcel_Cell $cell) {
65
+ if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
66
+ $this->_storeData();
67
+ }
68
+
69
+ $this->_currentObjectID = $pCoord;
70
+ $this->_currentObject = $cell;
71
+ $this->_currentCellIsDirty = true;
72
+
73
+ return $cell;
74
+ } // function addCacheData()
75
+
76
+
77
+ /**
78
+ * Get cell at a specific coordinate
79
+ *
80
+ * @param string $pCoord Coordinate of the cell
81
+ * @throws PHPExcel_Exception
82
+ * @return PHPExcel_Cell Cell that was found, or null if not found
83
+ */
84
+ public function getCacheData($pCoord) {
85
+ if ($pCoord === $this->_currentObjectID) {
86
+ return $this->_currentObject;
87
+ }
88
+ $this->_storeData();
89
+
90
+ // Check if the entry that has been requested actually exists
91
+ if (!isset($this->_cellCache[$pCoord])) {
92
+ // Return null if requested entry doesn't exist in cache
93
+ return null;
94
+ }
95
+
96
+ // Set current entry to the requested entry
97
+ $this->_currentObjectID = $pCoord;
98
+ $this->_currentObject = igbinary_unserialize($this->_cellCache[$pCoord]);
99
+ // Re-attach this as the cell's parent
100
+ $this->_currentObject->attach($this);
101
+
102
+ // Return requested entry
103
+ return $this->_currentObject;
104
+ } // function getCacheData()
105
+
106
+
107
+ /**
108
+ * Get a list of all cell addresses currently held in cache
109
+ *
110
+ * @return string[]
111
+ */
112
+ public function getCellList() {
113
+ if ($this->_currentObjectID !== null) {
114
+ $this->_storeData();
115
+ }
116
+
117
+ return parent::getCellList();
118
+ }
119
+
120
+
121
+ /**
122
+ * Clear the cell collection and disconnect from our parent
123
+ *
124
+ * @return void
125
+ */
126
+ public function unsetWorksheetCells() {
127
+ if(!is_null($this->_currentObject)) {
128
+ $this->_currentObject->detach();
129
+ $this->_currentObject = $this->_currentObjectID = null;
130
+ }
131
+ $this->_cellCache = array();
132
+
133
+ // detach ourself from the worksheet, so that it can then delete this object successfully
134
+ $this->_parent = null;
135
+ } // function unsetWorksheetCells()
136
+
137
+
138
+ /**
139
+ * Identify whether the caching method is currently available
140
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
141
+ *
142
+ * @return boolean
143
+ */
144
+ public static function cacheMethodIsAvailable() {
145
+ if (!function_exists('igbinary_serialize')) {
146
+ return false;
147
+ }
148
+
149
+ return true;
150
+ }
151
+
152
+ }
{libraries → classes}/PHPExcel/CachedObjectStorage/Memcache.php RENAMED
@@ -1,312 +1,312 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_Memcache
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- class PHPExcel_CachedObjectStorage_Memcache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
-
38
- /**
39
- * Prefix used to uniquely identify cache data for this worksheet
40
- *
41
- * @var string
42
- */
43
- private $_cachePrefix = null;
44
-
45
- /**
46
- * Cache timeout
47
- *
48
- * @var integer
49
- */
50
- private $_cacheTime = 600;
51
-
52
- /**
53
- * Memcache interface
54
- *
55
- * @var resource
56
- */
57
- private $_memcache = null;
58
-
59
-
60
- /**
61
- * Store cell data in cache for the current cell object if it's "dirty",
62
- * and the 'nullify' the current cell object
63
- *
64
- * @return void
65
- * @throws PHPExcel_Exception
66
- */
67
- protected function _storeData() {
68
- if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
69
- $this->_currentObject->detach();
70
-
71
- $obj = serialize($this->_currentObject);
72
- if (!$this->_memcache->replace($this->_cachePrefix.$this->_currentObjectID.'.cache',$obj,NULL,$this->_cacheTime)) {
73
- if (!$this->_memcache->add($this->_cachePrefix.$this->_currentObjectID.'.cache',$obj,NULL,$this->_cacheTime)) {
74
- $this->__destruct();
75
- throw new PHPExcel_Exception('Failed to store cell '.$this->_currentObjectID.' in MemCache');
76
- }
77
- }
78
- $this->_currentCellIsDirty = false;
79
- }
80
- $this->_currentObjectID = $this->_currentObject = null;
81
- } // function _storeData()
82
-
83
-
84
- /**
85
- * Add or Update a cell in cache identified by coordinate address
86
- *
87
- * @param string $pCoord Coordinate address of the cell to update
88
- * @param PHPExcel_Cell $cell Cell to update
89
- * @return PHPExcel_Cell
90
- * @throws PHPExcel_Exception
91
- */
92
- public function addCacheData($pCoord, PHPExcel_Cell $cell) {
93
- if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
94
- $this->_storeData();
95
- }
96
- $this->_cellCache[$pCoord] = true;
97
-
98
- $this->_currentObjectID = $pCoord;
99
- $this->_currentObject = $cell;
100
- $this->_currentCellIsDirty = true;
101
-
102
- return $cell;
103
- } // function addCacheData()
104
-
105
-
106
- /**
107
- * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
108
- *
109
- * @param string $pCoord Coordinate address of the cell to check
110
- * @return boolean
111
- * @return boolean
112
- */
113
- public function isDataSet($pCoord) {
114
- // Check if the requested entry is the current object, or exists in the cache
115
- if (parent::isDataSet($pCoord)) {
116
- if ($this->_currentObjectID == $pCoord) {
117
- return true;
118
- }
119
- // Check if the requested entry still exists in Memcache
120
- $success = $this->_memcache->get($this->_cachePrefix.$pCoord.'.cache');
121
- if ($success === false) {
122
- // Entry no longer exists in Memcache, so clear it from the cache array
123
- parent::deleteCacheData($pCoord);
124
- throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in MemCache');
125
- }
126
- return true;
127
- }
128
- return false;
129
- } // function isDataSet()
130
-
131
-
132
- /**
133
- * Get cell at a specific coordinate
134
- *
135
- * @param string $pCoord Coordinate of the cell
136
- * @throws PHPExcel_Exception
137
- * @return PHPExcel_Cell Cell that was found, or null if not found
138
- */
139
- public function getCacheData($pCoord) {
140
- if ($pCoord === $this->_currentObjectID) {
141
- return $this->_currentObject;
142
- }
143
- $this->_storeData();
144
-
145
- // Check if the entry that has been requested actually exists
146
- if (parent::isDataSet($pCoord)) {
147
- $obj = $this->_memcache->get($this->_cachePrefix.$pCoord.'.cache');
148
- if ($obj === false) {
149
- // Entry no longer exists in Memcache, so clear it from the cache array
150
- parent::deleteCacheData($pCoord);
151
- throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in MemCache');
152
- }
153
- } else {
154
- // Return null if requested entry doesn't exist in cache
155
- return null;
156
- }
157
-
158
- // Set current entry to the requested entry
159
- $this->_currentObjectID = $pCoord;
160
- $this->_currentObject = unserialize($obj);
161
- // Re-attach this as the cell's parent
162
- $this->_currentObject->attach($this);
163
-
164
- // Return requested entry
165
- return $this->_currentObject;
166
- } // function getCacheData()
167
-
168
-
169
- /**
170
- * Get a list of all cell addresses currently held in cache
171
- *
172
- * @return string[]
173
- */
174
- public function getCellList() {
175
- if ($this->_currentObjectID !== null) {
176
- $this->_storeData();
177
- }
178
-
179
- return parent::getCellList();
180
- }
181
-
182
-
183
- /**
184
- * Delete a cell in cache identified by coordinate address
185
- *
186
- * @param string $pCoord Coordinate address of the cell to delete
187
- * @throws PHPExcel_Exception
188
- */
189
- public function deleteCacheData($pCoord) {
190
- // Delete the entry from Memcache
191
- $this->_memcache->delete($this->_cachePrefix.$pCoord.'.cache');
192
-
193
- // Delete the entry from our cell address array
194
- parent::deleteCacheData($pCoord);
195
- } // function deleteCacheData()
196
-
197
-
198
- /**
199
- * Clone the cell collection
200
- *
201
- * @param PHPExcel_Worksheet $parent The new worksheet
202
- * @return void
203
- */
204
- public function copyCellCollection(PHPExcel_Worksheet $parent) {
205
- parent::copyCellCollection($parent);
206
- // Get a new id for the new file name
207
- $baseUnique = $this->_getUniqueID();
208
- $newCachePrefix = substr(md5($baseUnique),0,8).'.';
209
- $cacheList = $this->getCellList();
210
- foreach($cacheList as $cellID) {
211
- if ($cellID != $this->_currentObjectID) {
212
- $obj = $this->_memcache->get($this->_cachePrefix.$cellID.'.cache');
213
- if ($obj === false) {
214
- // Entry no longer exists in Memcache, so clear it from the cache array
215
- parent::deleteCacheData($cellID);
216
- throw new PHPExcel_Exception('Cell entry '.$cellID.' no longer exists in MemCache');
217
- }
218
- if (!$this->_memcache->add($newCachePrefix.$cellID.'.cache',$obj,NULL,$this->_cacheTime)) {
219
- $this->__destruct();
220
- throw new PHPExcel_Exception('Failed to store cell '.$cellID.' in MemCache');
221
- }
222
- }
223
- }
224
- $this->_cachePrefix = $newCachePrefix;
225
- } // function copyCellCollection()
226
-
227
-
228
- /**
229
- * Clear the cell collection and disconnect from our parent
230
- *
231
- * @return void
232
- */
233
- public function unsetWorksheetCells() {
234
- if(!is_null($this->_currentObject)) {
235
- $this->_currentObject->detach();
236
- $this->_currentObject = $this->_currentObjectID = null;
237
- }
238
-
239
- // Flush the Memcache cache
240
- $this->__destruct();
241
-
242
- $this->_cellCache = array();
243
-
244
- // detach ourself from the worksheet, so that it can then delete this object successfully
245
- $this->_parent = null;
246
- } // function unsetWorksheetCells()
247
-
248
-
249
- /**
250
- * Initialise this new cell collection
251
- *
252
- * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
253
- * @param array of mixed $arguments Additional initialisation arguments
254
- */
255
- public function __construct(PHPExcel_Worksheet $parent, $arguments) {
256
- $memcacheServer = (isset($arguments['memcacheServer'])) ? $arguments['memcacheServer'] : 'localhost';
257
- $memcachePort = (isset($arguments['memcachePort'])) ? $arguments['memcachePort'] : 11211;
258
- $cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600;
259
-
260
- if (is_null($this->_cachePrefix)) {
261
- $baseUnique = $this->_getUniqueID();
262
- $this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
263
-
264
- // Set a new Memcache object and connect to the Memcache server
265
- $this->_memcache = new Memcache();
266
- if (!$this->_memcache->addServer($memcacheServer, $memcachePort, false, 50, 5, 5, true, array($this, 'failureCallback'))) {
267
- throw new PHPExcel_Exception('Could not connect to MemCache server at '.$memcacheServer.':'.$memcachePort);
268
- }
269
- $this->_cacheTime = $cacheTime;
270
-
271
- parent::__construct($parent);
272
- }
273
- } // function __construct()
274
-
275
-
276
- /**
277
- * Memcache error handler
278
- *
279
- * @param string $host Memcache server
280
- * @param integer $port Memcache port
281
- * @throws PHPExcel_Exception
282
- */
283
- public function failureCallback($host, $port) {
284
- throw new PHPExcel_Exception('memcache '.$host.':'.$port.' failed');
285
- }
286
-
287
-
288
- /**
289
- * Destroy this cell collection
290
- */
291
- public function __destruct() {
292
- $cacheList = $this->getCellList();
293
- foreach($cacheList as $cellID) {
294
- $this->_memcache->delete($this->_cachePrefix.$cellID.'.cache');
295
- }
296
- } // function __destruct()
297
-
298
- /**
299
- * Identify whether the caching method is currently available
300
- * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
301
- *
302
- * @return boolean
303
- */
304
- public static function cacheMethodIsAvailable() {
305
- if (!function_exists('memcache_add')) {
306
- return false;
307
- }
308
-
309
- return true;
310
- }
311
-
312
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_Memcache
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ class PHPExcel_CachedObjectStorage_Memcache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
+
38
+ /**
39
+ * Prefix used to uniquely identify cache data for this worksheet
40
+ *
41
+ * @var string
42
+ */
43
+ private $_cachePrefix = null;
44
+
45
+ /**
46
+ * Cache timeout
47
+ *
48
+ * @var integer
49
+ */
50
+ private $_cacheTime = 600;
51
+
52
+ /**
53
+ * Memcache interface
54
+ *
55
+ * @var resource
56
+ */
57
+ private $_memcache = null;
58
+
59
+
60
+ /**
61
+ * Store cell data in cache for the current cell object if it's "dirty",
62
+ * and the 'nullify' the current cell object
63
+ *
64
+ * @return void
65
+ * @throws PHPExcel_Exception
66
+ */
67
+ protected function _storeData() {
68
+ if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
69
+ $this->_currentObject->detach();
70
+
71
+ $obj = serialize($this->_currentObject);
72
+ if (!$this->_memcache->replace($this->_cachePrefix.$this->_currentObjectID.'.cache',$obj,NULL,$this->_cacheTime)) {
73
+ if (!$this->_memcache->add($this->_cachePrefix.$this->_currentObjectID.'.cache',$obj,NULL,$this->_cacheTime)) {
74
+ $this->__destruct();
75
+ throw new PHPExcel_Exception('Failed to store cell '.$this->_currentObjectID.' in MemCache');
76
+ }
77
+ }
78
+ $this->_currentCellIsDirty = false;
79
+ }
80
+ $this->_currentObjectID = $this->_currentObject = null;
81
+ } // function _storeData()
82
+
83
+
84
+ /**
85
+ * Add or Update a cell in cache identified by coordinate address
86
+ *
87
+ * @param string $pCoord Coordinate address of the cell to update
88
+ * @param PHPExcel_Cell $cell Cell to update
89
+ * @return PHPExcel_Cell
90
+ * @throws PHPExcel_Exception
91
+ */
92
+ public function addCacheData($pCoord, PHPExcel_Cell $cell) {
93
+ if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
94
+ $this->_storeData();
95
+ }
96
+ $this->_cellCache[$pCoord] = true;
97
+
98
+ $this->_currentObjectID = $pCoord;
99
+ $this->_currentObject = $cell;
100
+ $this->_currentCellIsDirty = true;
101
+
102
+ return $cell;
103
+ } // function addCacheData()
104
+
105
+
106
+ /**
107
+ * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
108
+ *
109
+ * @param string $pCoord Coordinate address of the cell to check
110
+ * @return boolean
111
+ * @return boolean
112
+ */
113
+ public function isDataSet($pCoord) {
114
+ // Check if the requested entry is the current object, or exists in the cache
115
+ if (parent::isDataSet($pCoord)) {
116
+ if ($this->_currentObjectID == $pCoord) {
117
+ return true;
118
+ }
119
+ // Check if the requested entry still exists in Memcache
120
+ $success = $this->_memcache->get($this->_cachePrefix.$pCoord.'.cache');
121
+ if ($success === false) {
122
+ // Entry no longer exists in Memcache, so clear it from the cache array
123
+ parent::deleteCacheData($pCoord);
124
+ throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in MemCache');
125
+ }
126
+ return true;
127
+ }
128
+ return false;
129
+ } // function isDataSet()
130
+
131
+
132
+ /**
133
+ * Get cell at a specific coordinate
134
+ *
135
+ * @param string $pCoord Coordinate of the cell
136
+ * @throws PHPExcel_Exception
137
+ * @return PHPExcel_Cell Cell that was found, or null if not found
138
+ */
139
+ public function getCacheData($pCoord) {
140
+ if ($pCoord === $this->_currentObjectID) {
141
+ return $this->_currentObject;
142
+ }
143
+ $this->_storeData();
144
+
145
+ // Check if the entry that has been requested actually exists
146
+ if (parent::isDataSet($pCoord)) {
147
+ $obj = $this->_memcache->get($this->_cachePrefix.$pCoord.'.cache');
148
+ if ($obj === false) {
149
+ // Entry no longer exists in Memcache, so clear it from the cache array
150
+ parent::deleteCacheData($pCoord);
151
+ throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in MemCache');
152
+ }
153
+ } else {
154
+ // Return null if requested entry doesn't exist in cache
155
+ return null;
156
+ }
157
+
158
+ // Set current entry to the requested entry
159
+ $this->_currentObjectID = $pCoord;
160
+ $this->_currentObject = unserialize($obj);
161
+ // Re-attach this as the cell's parent
162
+ $this->_currentObject->attach($this);
163
+
164
+ // Return requested entry
165
+ return $this->_currentObject;
166
+ } // function getCacheData()
167
+
168
+
169
+ /**
170
+ * Get a list of all cell addresses currently held in cache
171
+ *
172
+ * @return string[]
173
+ */
174
+ public function getCellList() {
175
+ if ($this->_currentObjectID !== null) {
176
+ $this->_storeData();
177
+ }
178
+
179
+ return parent::getCellList();
180
+ }
181
+
182
+
183
+ /**
184
+ * Delete a cell in cache identified by coordinate address
185
+ *
186
+ * @param string $pCoord Coordinate address of the cell to delete
187
+ * @throws PHPExcel_Exception
188
+ */
189
+ public function deleteCacheData($pCoord) {
190
+ // Delete the entry from Memcache
191
+ $this->_memcache->delete($this->_cachePrefix.$pCoord.'.cache');
192
+
193
+ // Delete the entry from our cell address array
194
+ parent::deleteCacheData($pCoord);
195
+ } // function deleteCacheData()
196
+
197
+
198
+ /**
199
+ * Clone the cell collection
200
+ *
201
+ * @param PHPExcel_Worksheet $parent The new worksheet
202
+ * @return void
203
+ */
204
+ public function copyCellCollection(PHPExcel_Worksheet $parent) {
205
+ parent::copyCellCollection($parent);
206
+ // Get a new id for the new file name
207
+ $baseUnique = $this->_getUniqueID();
208
+ $newCachePrefix = substr(md5($baseUnique),0,8).'.';
209
+ $cacheList = $this->getCellList();
210
+ foreach($cacheList as $cellID) {
211
+ if ($cellID != $this->_currentObjectID) {
212
+ $obj = $this->_memcache->get($this->_cachePrefix.$cellID.'.cache');
213
+ if ($obj === false) {
214
+ // Entry no longer exists in Memcache, so clear it from the cache array
215
+ parent::deleteCacheData($cellID);
216
+ throw new PHPExcel_Exception('Cell entry '.$cellID.' no longer exists in MemCache');
217
+ }
218
+ if (!$this->_memcache->add($newCachePrefix.$cellID.'.cache',$obj,NULL,$this->_cacheTime)) {
219
+ $this->__destruct();
220
+ throw new PHPExcel_Exception('Failed to store cell '.$cellID.' in MemCache');
221
+ }
222
+ }
223
+ }
224
+ $this->_cachePrefix = $newCachePrefix;
225
+ } // function copyCellCollection()
226
+
227
+
228
+ /**
229
+ * Clear the cell collection and disconnect from our parent
230
+ *
231
+ * @return void
232
+ */
233
+ public function unsetWorksheetCells() {
234
+ if(!is_null($this->_currentObject)) {
235
+ $this->_currentObject->detach();
236
+ $this->_currentObject = $this->_currentObjectID = null;
237
+ }
238
+
239
+ // Flush the Memcache cache
240
+ $this->__destruct();
241
+
242
+ $this->_cellCache = array();
243
+
244
+ // detach ourself from the worksheet, so that it can then delete this object successfully
245
+ $this->_parent = null;
246
+ } // function unsetWorksheetCells()
247
+
248
+
249
+ /**
250
+ * Initialise this new cell collection
251
+ *
252
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
253
+ * @param array of mixed $arguments Additional initialisation arguments
254
+ */
255
+ public function __construct(PHPExcel_Worksheet $parent, $arguments) {
256
+ $memcacheServer = (isset($arguments['memcacheServer'])) ? $arguments['memcacheServer'] : 'localhost';
257
+ $memcachePort = (isset($arguments['memcachePort'])) ? $arguments['memcachePort'] : 11211;
258
+ $cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600;
259
+
260
+ if (is_null($this->_cachePrefix)) {
261
+ $baseUnique = $this->_getUniqueID();
262
+ $this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
263
+
264
+ // Set a new Memcache object and connect to the Memcache server
265
+ $this->_memcache = new Memcache();
266
+ if (!$this->_memcache->addServer($memcacheServer, $memcachePort, false, 50, 5, 5, true, array($this, 'failureCallback'))) {
267
+ throw new PHPExcel_Exception('Could not connect to MemCache server at '.$memcacheServer.':'.$memcachePort);
268
+ }
269
+ $this->_cacheTime = $cacheTime;
270
+
271
+ parent::__construct($parent);
272
+ }
273
+ } // function __construct()
274
+
275
+
276
+ /**
277
+ * Memcache error handler
278
+ *
279
+ * @param string $host Memcache server
280
+ * @param integer $port Memcache port
281
+ * @throws PHPExcel_Exception
282
+ */
283
+ public function failureCallback($host, $port) {
284
+ throw new PHPExcel_Exception('memcache '.$host.':'.$port.' failed');
285
+ }
286
+
287
+
288
+ /**
289
+ * Destroy this cell collection
290
+ */
291
+ public function __destruct() {
292
+ $cacheList = $this->getCellList();
293
+ foreach($cacheList as $cellID) {
294
+ $this->_memcache->delete($this->_cachePrefix.$cellID.'.cache');
295
+ }
296
+ } // function __destruct()
297
+
298
+ /**
299
+ * Identify whether the caching method is currently available
300
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
301
+ *
302
+ * @return boolean
303
+ */
304
+ public static function cacheMethodIsAvailable() {
305
+ if (!function_exists('memcache_add')) {
306
+ return false;
307
+ }
308
+
309
+ return true;
310
+ }
311
+
312
+ }
{libraries → classes}/PHPExcel/CachedObjectStorage/Memory.php RENAMED
@@ -1,125 +1,125 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_Memory
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- class PHPExcel_CachedObjectStorage_Memory extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
-
38
- /**
39
- * Dummy method callable from CacheBase, but unused by Memory cache
40
- *
41
- * @return void
42
- */
43
- protected function _storeData() {
44
- } // function _storeData()
45
-
46
- /**
47
- * Add or Update a cell in cache identified by coordinate address
48
- *
49
- * @param string $pCoord Coordinate address of the cell to update
50
- * @param PHPExcel_Cell $cell Cell to update
51
- * @return PHPExcel_Cell
52
- * @throws PHPExcel_Exception
53
- */
54
- public function addCacheData($pCoord, PHPExcel_Cell $cell) {
55
- $this->_cellCache[$pCoord] = $cell;
56
-
57
- // Set current entry to the new/updated entry
58
- $this->_currentObjectID = $pCoord;
59
-
60
- return $cell;
61
- } // function addCacheData()
62
-
63
-
64
- /**
65
- * Get cell at a specific coordinate
66
- *
67
- * @param string $pCoord Coordinate of the cell
68
- * @throws PHPExcel_Exception
69
- * @return PHPExcel_Cell Cell that was found, or null if not found
70
- */
71
- public function getCacheData($pCoord) {
72
- // Check if the entry that has been requested actually exists
73
- if (!isset($this->_cellCache[$pCoord])) {
74
- $this->_currentObjectID = NULL;
75
- // Return null if requested entry doesn't exist in cache
76
- return null;
77
- }
78
-
79
- // Set current entry to the requested entry
80
- $this->_currentObjectID = $pCoord;
81
-
82
- // Return requested entry
83
- return $this->_cellCache[$pCoord];
84
- } // function getCacheData()
85
-
86
-
87
- /**
88
- * Clone the cell collection
89
- *
90
- * @param PHPExcel_Worksheet $parent The new worksheet
91
- * @return void
92
- */
93
- public function copyCellCollection(PHPExcel_Worksheet $parent) {
94
- parent::copyCellCollection($parent);
95
-
96
- $newCollection = array();
97
- foreach($this->_cellCache as $k => &$cell) {
98
- $newCollection[$k] = clone $cell;
99
- $newCollection[$k]->attach($this);
100
- }
101
-
102
- $this->_cellCache = $newCollection;
103
- }
104
-
105
-
106
- /**
107
- * Clear the cell collection and disconnect from our parent
108
- *
109
- * @return void
110
- */
111
- public function unsetWorksheetCells() {
112
- // Because cells are all stored as intact objects in memory, we need to detach each one from the parent
113
- foreach($this->_cellCache as $k => &$cell) {
114
- $cell->detach();
115
- $this->_cellCache[$k] = null;
116
- }
117
- unset($cell);
118
-
119
- $this->_cellCache = array();
120
-
121
- // detach ourself from the worksheet, so that it can then delete this object successfully
122
- $this->_parent = null;
123
- } // function unsetWorksheetCells()
124
-
125
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_Memory
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ class PHPExcel_CachedObjectStorage_Memory extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
+
38
+ /**
39
+ * Dummy method callable from CacheBase, but unused by Memory cache
40
+ *
41
+ * @return void
42
+ */
43
+ protected function _storeData() {
44
+ } // function _storeData()
45
+
46
+ /**
47
+ * Add or Update a cell in cache identified by coordinate address
48
+ *
49
+ * @param string $pCoord Coordinate address of the cell to update
50
+ * @param PHPExcel_Cell $cell Cell to update
51
+ * @return PHPExcel_Cell
52
+ * @throws PHPExcel_Exception
53
+ */
54
+ public function addCacheData($pCoord, PHPExcel_Cell $cell) {
55
+ $this->_cellCache[$pCoord] = $cell;
56
+
57
+ // Set current entry to the new/updated entry
58
+ $this->_currentObjectID = $pCoord;
59
+
60
+ return $cell;
61
+ } // function addCacheData()
62
+
63
+
64
+ /**
65
+ * Get cell at a specific coordinate
66
+ *
67
+ * @param string $pCoord Coordinate of the cell
68
+ * @throws PHPExcel_Exception
69
+ * @return PHPExcel_Cell Cell that was found, or null if not found
70
+ */
71
+ public function getCacheData($pCoord) {
72
+ // Check if the entry that has been requested actually exists
73
+ if (!isset($this->_cellCache[$pCoord])) {
74
+ $this->_currentObjectID = NULL;
75
+ // Return null if requested entry doesn't exist in cache
76
+ return null;
77
+ }
78
+
79
+ // Set current entry to the requested entry
80
+ $this->_currentObjectID = $pCoord;
81
+
82
+ // Return requested entry
83
+ return $this->_cellCache[$pCoord];
84
+ } // function getCacheData()
85
+
86
+
87
+ /**
88
+ * Clone the cell collection
89
+ *
90
+ * @param PHPExcel_Worksheet $parent The new worksheet
91
+ * @return void
92
+ */
93
+ public function copyCellCollection(PHPExcel_Worksheet $parent) {
94
+ parent::copyCellCollection($parent);
95
+
96
+ $newCollection = array();
97
+ foreach($this->_cellCache as $k => &$cell) {
98
+ $newCollection[$k] = clone $cell;
99
+ $newCollection[$k]->attach($this);
100
+ }
101
+
102
+ $this->_cellCache = $newCollection;
103
+ }
104
+
105
+
106
+ /**
107
+ * Clear the cell collection and disconnect from our parent
108
+ *
109
+ * @return void
110
+ */
111
+ public function unsetWorksheetCells() {
112
+ // Because cells are all stored as intact objects in memory, we need to detach each one from the parent
113
+ foreach($this->_cellCache as $k => &$cell) {
114
+ $cell->detach();
115
+ $this->_cellCache[$k] = null;
116
+ }
117
+ unset($cell);
118
+
119
+ $this->_cellCache = array();
120
+
121
+ // detach ourself from the worksheet, so that it can then delete this object successfully
122
+ $this->_parent = null;
123
+ } // function unsetWorksheetCells()
124
+
125
+ }
{libraries → classes}/PHPExcel/CachedObjectStorage/MemoryGZip.php RENAMED
@@ -1,137 +1,137 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_MemoryGZip
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- class PHPExcel_CachedObjectStorage_MemoryGZip extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
-
38
- /**
39
- * Store cell data in cache for the current cell object if it's "dirty",
40
- * and the 'nullify' the current cell object
41
- *
42
- * @return void
43
- * @throws PHPExcel_Exception
44
- */
45
- protected function _storeData() {
46
- if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
47
- $this->_currentObject->detach();
48
-
49
- $this->_cellCache[$this->_currentObjectID] = gzdeflate(serialize($this->_currentObject));
50
- $this->_currentCellIsDirty = false;
51
- }
52
- $this->_currentObjectID = $this->_currentObject = null;
53
- } // function _storeData()
54
-
55
-
56
- /**
57
- * Add or Update a cell in cache identified by coordinate address
58
- *
59
- * @param string $pCoord Coordinate address of the cell to update
60
- * @param PHPExcel_Cell $cell Cell to update
61
- * @return PHPExcel_Cell
62
- * @throws PHPExcel_Exception
63
- */
64
- public function addCacheData($pCoord, PHPExcel_Cell $cell) {
65
- if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
66
- $this->_storeData();
67
- }
68
-
69
- $this->_currentObjectID = $pCoord;
70
- $this->_currentObject = $cell;
71
- $this->_currentCellIsDirty = true;
72
-
73
- return $cell;
74
- } // function addCacheData()
75
-
76
-
77
- /**
78
- * Get cell at a specific coordinate
79
- *
80
- * @param string $pCoord Coordinate of the cell
81
- * @throws PHPExcel_Exception
82
- * @return PHPExcel_Cell Cell that was found, or null if not found
83
- */
84
- public function getCacheData($pCoord) {
85
- if ($pCoord === $this->_currentObjectID) {
86
- return $this->_currentObject;
87
- }
88
- $this->_storeData();
89
-
90
- // Check if the entry that has been requested actually exists
91
- if (!isset($this->_cellCache[$pCoord])) {
92
- // Return null if requested entry doesn't exist in cache
93
- return null;
94
- }
95
-
96
- // Set current entry to the requested entry
97
- $this->_currentObjectID = $pCoord;
98
- $this->_currentObject = unserialize(gzinflate($this->_cellCache[$pCoord]));
99
- // Re-attach this as the cell's parent
100
- $this->_currentObject->attach($this);
101
-
102
- // Return requested entry
103
- return $this->_currentObject;
104
- } // function getCacheData()
105
-
106
-
107
- /**
108
- * Get a list of all cell addresses currently held in cache
109
- *
110
- * @return string[]
111
- */
112
- public function getCellList() {
113
- if ($this->_currentObjectID !== null) {
114
- $this->_storeData();
115
- }
116
-
117
- return parent::getCellList();
118
- }
119
-
120
-
121
- /**
122
- * Clear the cell collection and disconnect from our parent
123
- *
124
- * @return void
125
- */
126
- public function unsetWorksheetCells() {
127
- if(!is_null($this->_currentObject)) {
128
- $this->_currentObject->detach();
129
- $this->_currentObject = $this->_currentObjectID = null;
130
- }
131
- $this->_cellCache = array();
132
-
133
- // detach ourself from the worksheet, so that it can then delete this object successfully
134
- $this->_parent = null;
135
- } // function unsetWorksheetCells()
136
-
137
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_MemoryGZip
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ class PHPExcel_CachedObjectStorage_MemoryGZip extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
+
38
+ /**
39
+ * Store cell data in cache for the current cell object if it's "dirty",
40
+ * and the 'nullify' the current cell object
41
+ *
42
+ * @return void
43
+ * @throws PHPExcel_Exception
44
+ */
45
+ protected function _storeData() {
46
+ if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
47
+ $this->_currentObject->detach();
48
+
49
+ $this->_cellCache[$this->_currentObjectID] = gzdeflate(serialize($this->_currentObject));
50
+ $this->_currentCellIsDirty = false;
51
+ }
52
+ $this->_currentObjectID = $this->_currentObject = null;
53
+ } // function _storeData()
54
+
55
+
56
+ /**
57
+ * Add or Update a cell in cache identified by coordinate address
58
+ *
59
+ * @param string $pCoord Coordinate address of the cell to update
60
+ * @param PHPExcel_Cell $cell Cell to update
61
+ * @return PHPExcel_Cell
62
+ * @throws PHPExcel_Exception
63
+ */
64
+ public function addCacheData($pCoord, PHPExcel_Cell $cell) {
65
+ if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
66
+ $this->_storeData();
67
+ }
68
+
69
+ $this->_currentObjectID = $pCoord;
70
+ $this->_currentObject = $cell;
71
+ $this->_currentCellIsDirty = true;
72
+
73
+ return $cell;
74
+ } // function addCacheData()
75
+
76
+
77
+ /**
78
+ * Get cell at a specific coordinate
79
+ *
80
+ * @param string $pCoord Coordinate of the cell
81
+ * @throws PHPExcel_Exception
82
+ * @return PHPExcel_Cell Cell that was found, or null if not found
83
+ */
84
+ public function getCacheData($pCoord) {
85
+ if ($pCoord === $this->_currentObjectID) {
86
+ return $this->_currentObject;
87
+ }
88
+ $this->_storeData();
89
+
90
+ // Check if the entry that has been requested actually exists
91
+ if (!isset($this->_cellCache[$pCoord])) {
92
+ // Return null if requested entry doesn't exist in cache
93
+ return null;
94
+ }
95
+
96
+ // Set current entry to the requested entry
97
+ $this->_currentObjectID = $pCoord;
98
+ $this->_currentObject = unserialize(gzinflate($this->_cellCache[$pCoord]));
99
+ // Re-attach this as the cell's parent
100
+ $this->_currentObject->attach($this);
101
+
102
+ // Return requested entry
103
+ return $this->_currentObject;
104
+ } // function getCacheData()
105
+
106
+
107
+ /**
108
+ * Get a list of all cell addresses currently held in cache
109
+ *
110
+ * @return string[]
111
+ */
112
+ public function getCellList() {
113
+ if ($this->_currentObjectID !== null) {
114
+ $this->_storeData();
115
+ }
116
+
117
+ return parent::getCellList();
118
+ }
119
+
120
+
121
+ /**
122
+ * Clear the cell collection and disconnect from our parent
123
+ *
124
+ * @return void
125
+ */
126
+ public function unsetWorksheetCells() {
127
+ if(!is_null($this->_currentObject)) {
128
+ $this->_currentObject->detach();
129
+ $this->_currentObject = $this->_currentObjectID = null;
130
+ }
131
+ $this->_cellCache = array();
132
+
133
+ // detach ourself from the worksheet, so that it can then delete this object successfully
134
+ $this->_parent = null;
135
+ } // function unsetWorksheetCells()
136
+
137
+ }
{libraries → classes}/PHPExcel/CachedObjectStorage/MemorySerialized.php RENAMED
@@ -1,137 +1,137 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_MemorySerialized
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- class PHPExcel_CachedObjectStorage_MemorySerialized extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
-
38
- /**
39
- * Store cell data in cache for the current cell object if it's "dirty",
40
- * and the 'nullify' the current cell object
41
- *
42
- * @return void
43
- * @throws PHPExcel_Exception
44
- */
45
- protected function _storeData() {
46
- if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
47
- $this->_currentObject->detach();
48
-
49
- $this->_cellCache[$this->_currentObjectID] = serialize($this->_currentObject);
50
- $this->_currentCellIsDirty = false;
51
- }
52
- $this->_currentObjectID = $this->_currentObject = null;
53
- } // function _storeData()
54
-
55
-
56
- /**
57
- * Add or Update a cell in cache identified by coordinate address
58
- *
59
- * @param string $pCoord Coordinate address of the cell to update
60
- * @param PHPExcel_Cell $cell Cell to update
61
- * @return PHPExcel_Cell
62
- * @throws PHPExcel_Exception
63
- */
64
- public function addCacheData($pCoord, PHPExcel_Cell $cell) {
65
- if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
66
- $this->_storeData();
67
- }
68
-
69
- $this->_currentObjectID = $pCoord;
70
- $this->_currentObject = $cell;
71
- $this->_currentCellIsDirty = true;
72
-
73
- return $cell;
74
- } // function addCacheData()
75
-
76
-
77
- /**
78
- * Get cell at a specific coordinate
79
- *
80
- * @param string $pCoord Coordinate of the cell
81
- * @throws PHPExcel_Exception
82
- * @return PHPExcel_Cell Cell that was found, or null if not found
83
- */
84
- public function getCacheData($pCoord) {
85
- if ($pCoord === $this->_currentObjectID) {
86
- return $this->_currentObject;
87
- }
88
- $this->_storeData();
89
-
90
- // Check if the entry that has been requested actually exists
91
- if (!isset($this->_cellCache[$pCoord])) {
92
- // Return null if requested entry doesn't exist in cache
93
- return null;
94
- }
95
-
96
- // Set current entry to the requested entry
97
- $this->_currentObjectID = $pCoord;
98
- $this->_currentObject = unserialize($this->_cellCache[$pCoord]);
99
- // Re-attach this as the cell's parent
100
- $this->_currentObject->attach($this);
101
-
102
- // Return requested entry
103
- return $this->_currentObject;
104
- } // function getCacheData()
105
-
106
-
107
- /**
108
- * Get a list of all cell addresses currently held in cache
109
- *
110
- * @return string[]
111
- */
112
- public function getCellList() {
113
- if ($this->_currentObjectID !== null) {
114
- $this->_storeData();
115
- }
116
-
117
- return parent::getCellList();
118
- }
119
-
120
-
121
- /**
122
- * Clear the cell collection and disconnect from our parent
123
- *
124
- * @return void
125
- */
126
- public function unsetWorksheetCells() {
127
- if(!is_null($this->_currentObject)) {
128
- $this->_currentObject->detach();
129
- $this->_currentObject = $this->_currentObjectID = null;
130
- }
131
- $this->_cellCache = array();
132
-
133
- // detach ourself from the worksheet, so that it can then delete this object successfully
134
- $this->_parent = null;
135
- } // function unsetWorksheetCells()
136
-
137
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_MemorySerialized
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ class PHPExcel_CachedObjectStorage_MemorySerialized extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
+
38
+ /**
39
+ * Store cell data in cache for the current cell object if it's "dirty",
40
+ * and the 'nullify' the current cell object
41
+ *
42
+ * @return void
43
+ * @throws PHPExcel_Exception
44
+ */
45
+ protected function _storeData() {
46
+ if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
47
+ $this->_currentObject->detach();
48
+
49
+ $this->_cellCache[$this->_currentObjectID] = serialize($this->_currentObject);
50
+ $this->_currentCellIsDirty = false;
51
+ }
52
+ $this->_currentObjectID = $this->_currentObject = null;
53
+ } // function _storeData()
54
+
55
+
56
+ /**
57
+ * Add or Update a cell in cache identified by coordinate address
58
+ *
59
+ * @param string $pCoord Coordinate address of the cell to update
60
+ * @param PHPExcel_Cell $cell Cell to update
61
+ * @return PHPExcel_Cell
62
+ * @throws PHPExcel_Exception
63
+ */
64
+ public function addCacheData($pCoord, PHPExcel_Cell $cell) {
65
+ if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
66
+ $this->_storeData();
67
+ }
68
+
69
+ $this->_currentObjectID = $pCoord;
70
+ $this->_currentObject = $cell;
71
+ $this->_currentCellIsDirty = true;
72
+
73
+ return $cell;
74
+ } // function addCacheData()
75
+
76
+
77
+ /**
78
+ * Get cell at a specific coordinate
79
+ *
80
+ * @param string $pCoord Coordinate of the cell
81
+ * @throws PHPExcel_Exception
82
+ * @return PHPExcel_Cell Cell that was found, or null if not found
83
+ */
84
+ public function getCacheData($pCoord) {
85
+ if ($pCoord === $this->_currentObjectID) {
86
+ return $this->_currentObject;
87
+ }
88
+ $this->_storeData();
89
+
90
+ // Check if the entry that has been requested actually exists
91
+ if (!isset($this->_cellCache[$pCoord])) {
92
+ // Return null if requested entry doesn't exist in cache
93
+ return null;
94
+ }
95
+
96
+ // Set current entry to the requested entry
97
+ $this->_currentObjectID = $pCoord;
98
+ $this->_currentObject = unserialize($this->_cellCache[$pCoord]);
99
+ // Re-attach this as the cell's parent
100
+ $this->_currentObject->attach($this);
101
+
102
+ // Return requested entry
103
+ return $this->_currentObject;
104
+ } // function getCacheData()
105
+
106
+
107
+ /**
108
+ * Get a list of all cell addresses currently held in cache
109
+ *
110
+ * @return string[]
111
+ */
112
+ public function getCellList() {
113
+ if ($this->_currentObjectID !== null) {
114
+ $this->_storeData();
115
+ }
116
+
117
+ return parent::getCellList();
118
+ }
119
+
120
+
121
+ /**
122
+ * Clear the cell collection and disconnect from our parent
123
+ *
124
+ * @return void
125
+ */
126
+ public function unsetWorksheetCells() {
127
+ if(!is_null($this->_currentObject)) {
128
+ $this->_currentObject->detach();
129
+ $this->_currentObject = $this->_currentObjectID = null;
130
+ }
131
+ $this->_cellCache = array();
132
+
133
+ // detach ourself from the worksheet, so that it can then delete this object successfully
134
+ $this->_parent = null;
135
+ } // function unsetWorksheetCells()
136
+
137
+ }
{libraries → classes}/PHPExcel/CachedObjectStorage/PHPTemp.php RENAMED
@@ -1,206 +1,206 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_PHPTemp
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- class PHPExcel_CachedObjectStorage_PHPTemp extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
-
38
- /**
39
- * Name of the file for this cache
40
- *
41
- * @var string
42
- */
43
- private $_fileHandle = null;
44
-
45
- /**
46
- * Memory limit to use before reverting to file cache
47
- *
48
- * @var integer
49
- */
50
- private $_memoryCacheSize = null;
51
-
52
- /**
53
- * Store cell data in cache for the current cell object if it's "dirty",
54
- * and the 'nullify' the current cell object
55
- *
56
- * @return void
57
- * @throws PHPExcel_Exception
58
- */
59
- protected function _storeData() {
60
- if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
61
- $this->_currentObject->detach();
62
-
63
- fseek($this->_fileHandle,0,SEEK_END);
64
-
65
- $this->_cellCache[$this->_currentObjectID] = array(
66
- 'ptr' => ftell($this->_fileHandle),
67
- 'sz' => fwrite($this->_fileHandle, serialize($this->_currentObject))
68
- );
69
- $this->_currentCellIsDirty = false;
70
- }
71
- $this->_currentObjectID = $this->_currentObject = null;
72
- } // function _storeData()
73
-
74
-
75
- /**
76
- * Add or Update a cell in cache identified by coordinate address
77
- *
78
- * @param string $pCoord Coordinate address of the cell to update
79
- * @param PHPExcel_Cell $cell Cell to update
80
- * @return PHPExcel_Cell
81
- * @throws PHPExcel_Exception
82
- */
83
- public function addCacheData($pCoord, PHPExcel_Cell $cell) {
84
- if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
85
- $this->_storeData();
86
- }
87
-
88
- $this->_currentObjectID = $pCoord;
89
- $this->_currentObject = $cell;
90
- $this->_currentCellIsDirty = true;
91
-
92
- return $cell;
93
- } // function addCacheData()
94
-
95
-
96
- /**
97
- * Get cell at a specific coordinate
98
- *
99
- * @param string $pCoord Coordinate of the cell
100
- * @throws PHPExcel_Exception
101
- * @return PHPExcel_Cell Cell that was found, or null if not found
102
- */
103
- public function getCacheData($pCoord) {
104
- if ($pCoord === $this->_currentObjectID) {
105
- return $this->_currentObject;
106
- }
107
- $this->_storeData();
108
-
109
- // Check if the entry that has been requested actually exists
110
- if (!isset($this->_cellCache[$pCoord])) {
111
- // Return null if requested entry doesn't exist in cache
112
- return null;
113
- }
114
-
115
- // Set current entry to the requested entry
116
- $this->_currentObjectID = $pCoord;
117
- fseek($this->_fileHandle,$this->_cellCache[$pCoord]['ptr']);
118
- $this->_currentObject = unserialize(fread($this->_fileHandle,$this->_cellCache[$pCoord]['sz']));
119
- // Re-attach this as the cell's parent
120
- $this->_currentObject->attach($this);
121
-
122
- // Return requested entry
123
- return $this->_currentObject;
124
- } // function getCacheData()
125
-
126
-
127
- /**
128
- * Get a list of all cell addresses currently held in cache
129
- *
130
- * @return string[]
131
- */
132
- public function getCellList() {
133
- if ($this->_currentObjectID !== null) {
134
- $this->_storeData();
135
- }
136
-
137
- return parent::getCellList();
138
- }
139
-
140
-
141
- /**
142
- * Clone the cell collection
143
- *
144
- * @param PHPExcel_Worksheet $parent The new worksheet
145
- * @return void
146
- */
147
- public function copyCellCollection(PHPExcel_Worksheet $parent) {
148
- parent::copyCellCollection($parent);
149
- // Open a new stream for the cell cache data
150
- $newFileHandle = fopen('php://temp/maxmemory:'.$this->_memoryCacheSize,'a+');
151
- // Copy the existing cell cache data to the new stream
152
- fseek($this->_fileHandle,0);
153
- while (!feof($this->_fileHandle)) {
154
- fwrite($newFileHandle,fread($this->_fileHandle, 1024));
155
- }
156
- $this->_fileHandle = $newFileHandle;
157
- } // function copyCellCollection()
158
-
159
-
160
- /**
161
- * Clear the cell collection and disconnect from our parent
162
- *
163
- * @return void
164
- */
165
- public function unsetWorksheetCells() {
166
- if(!is_null($this->_currentObject)) {
167
- $this->_currentObject->detach();
168
- $this->_currentObject = $this->_currentObjectID = null;
169
- }
170
- $this->_cellCache = array();
171
-
172
- // detach ourself from the worksheet, so that it can then delete this object successfully
173
- $this->_parent = null;
174
-
175
- // Close down the php://temp file
176
- $this->__destruct();
177
- } // function unsetWorksheetCells()
178
-
179
-
180
- /**
181
- * Initialise this new cell collection
182
- *
183
- * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
184
- * @param array of mixed $arguments Additional initialisation arguments
185
- */
186
- public function __construct(PHPExcel_Worksheet $parent, $arguments) {
187
- $this->_memoryCacheSize = (isset($arguments['memoryCacheSize'])) ? $arguments['memoryCacheSize'] : '1MB';
188
-
189
- parent::__construct($parent);
190
- if (is_null($this->_fileHandle)) {
191
- $this->_fileHandle = fopen('php://temp/maxmemory:'.$this->_memoryCacheSize,'a+');
192
- }
193
- } // function __construct()
194
-
195
-
196
- /**
197
- * Destroy this cell collection
198
- */
199
- public function __destruct() {
200
- if (!is_null($this->_fileHandle)) {
201
- fclose($this->_fileHandle);
202
- }
203
- $this->_fileHandle = null;
204
- } // function __destruct()
205
-
206
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_PHPTemp
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ class PHPExcel_CachedObjectStorage_PHPTemp extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
+
38
+ /**
39
+ * Name of the file for this cache
40
+ *
41
+ * @var string
42
+ */
43
+ private $_fileHandle = null;
44
+
45
+ /**
46
+ * Memory limit to use before reverting to file cache
47
+ *
48
+ * @var integer
49
+ */
50
+ private $_memoryCacheSize = null;
51
+
52
+ /**
53
+ * Store cell data in cache for the current cell object if it's "dirty",
54
+ * and the 'nullify' the current cell object
55
+ *
56
+ * @return void
57
+ * @throws PHPExcel_Exception
58
+ */
59
+ protected function _storeData() {
60
+ if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
61
+ $this->_currentObject->detach();
62
+
63
+ fseek($this->_fileHandle,0,SEEK_END);
64
+
65
+ $this->_cellCache[$this->_currentObjectID] = array(
66
+ 'ptr' => ftell($this->_fileHandle),
67
+ 'sz' => fwrite($this->_fileHandle, serialize($this->_currentObject))
68
+ );
69
+ $this->_currentCellIsDirty = false;
70
+ }
71
+ $this->_currentObjectID = $this->_currentObject = null;
72
+ } // function _storeData()
73
+
74
+
75
+ /**
76
+ * Add or Update a cell in cache identified by coordinate address
77
+ *
78
+ * @param string $pCoord Coordinate address of the cell to update
79
+ * @param PHPExcel_Cell $cell Cell to update
80
+ * @return PHPExcel_Cell
81
+ * @throws PHPExcel_Exception
82
+ */
83
+ public function addCacheData($pCoord, PHPExcel_Cell $cell) {
84
+ if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
85
+ $this->_storeData();
86
+ }
87
+
88
+ $this->_currentObjectID = $pCoord;
89
+ $this->_currentObject = $cell;
90
+ $this->_currentCellIsDirty = true;
91
+
92
+ return $cell;
93
+ } // function addCacheData()
94
+
95
+
96
+ /**
97
+ * Get cell at a specific coordinate
98
+ *
99
+ * @param string $pCoord Coordinate of the cell
100
+ * @throws PHPExcel_Exception
101
+ * @return PHPExcel_Cell Cell that was found, or null if not found
102
+ */
103
+ public function getCacheData($pCoord) {
104
+ if ($pCoord === $this->_currentObjectID) {
105
+ return $this->_currentObject;
106
+ }
107
+ $this->_storeData();
108
+
109
+ // Check if the entry that has been requested actually exists
110
+ if (!isset($this->_cellCache[$pCoord])) {
111
+ // Return null if requested entry doesn't exist in cache
112
+ return null;
113
+ }
114
+
115
+ // Set current entry to the requested entry
116
+ $this->_currentObjectID = $pCoord;
117
+ fseek($this->_fileHandle,$this->_cellCache[$pCoord]['ptr']);
118
+ $this->_currentObject = unserialize(fread($this->_fileHandle,$this->_cellCache[$pCoord]['sz']));
119
+ // Re-attach this as the cell's parent
120
+ $this->_currentObject->attach($this);
121
+
122
+ // Return requested entry
123
+ return $this->_currentObject;
124
+ } // function getCacheData()
125
+
126
+
127
+ /**
128
+ * Get a list of all cell addresses currently held in cache
129
+ *
130
+ * @return string[]
131
+ */
132
+ public function getCellList() {
133
+ if ($this->_currentObjectID !== null) {
134
+ $this->_storeData();
135
+ }
136
+
137
+ return parent::getCellList();
138
+ }
139
+
140
+
141
+ /**
142
+ * Clone the cell collection
143
+ *
144
+ * @param PHPExcel_Worksheet $parent The new worksheet
145
+ * @return void
146
+ */
147
+ public function copyCellCollection(PHPExcel_Worksheet $parent) {
148
+ parent::copyCellCollection($parent);
149
+ // Open a new stream for the cell cache data
150
+ $newFileHandle = fopen('php://temp/maxmemory:'.$this->_memoryCacheSize,'a+');
151
+ // Copy the existing cell cache data to the new stream
152
+ fseek($this->_fileHandle,0);
153
+ while (!feof($this->_fileHandle)) {
154
+ fwrite($newFileHandle,fread($this->_fileHandle, 1024));
155
+ }
156
+ $this->_fileHandle = $newFileHandle;
157
+ } // function copyCellCollection()
158
+
159
+
160
+ /**
161
+ * Clear the cell collection and disconnect from our parent
162
+ *
163
+ * @return void
164
+ */
165
+ public function unsetWorksheetCells() {
166
+ if(!is_null($this->_currentObject)) {
167
+ $this->_currentObject->detach();
168
+ $this->_currentObject = $this->_currentObjectID = null;
169
+ }
170
+ $this->_cellCache = array();
171
+
172
+ // detach ourself from the worksheet, so that it can then delete this object successfully
173
+ $this->_parent = null;
174
+
175
+ // Close down the php://temp file
176
+ $this->__destruct();
177
+ } // function unsetWorksheetCells()
178
+
179
+
180
+ /**
181
+ * Initialise this new cell collection
182
+ *
183
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
184
+ * @param array of mixed $arguments Additional initialisation arguments
185
+ */
186
+ public function __construct(PHPExcel_Worksheet $parent, $arguments) {
187
+ $this->_memoryCacheSize = (isset($arguments['memoryCacheSize'])) ? $arguments['memoryCacheSize'] : '1MB';
188
+
189
+ parent::__construct($parent);
190
+ if (is_null($this->_fileHandle)) {
191
+ $this->_fileHandle = fopen('php://temp/maxmemory:'.$this->_memoryCacheSize,'a+');
192
+ }
193
+ } // function __construct()
194
+
195
+
196
+ /**
197
+ * Destroy this cell collection
198
+ */
199
+ public function __destruct() {
200
+ if (!is_null($this->_fileHandle)) {
201
+ fclose($this->_fileHandle);
202
+ }
203
+ $this->_fileHandle = null;
204
+ } // function __destruct()
205
+
206
+ }
{libraries → classes}/PHPExcel/CachedObjectStorage/SQLite.php RENAMED
@@ -1,306 +1,306 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_SQLite
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- class PHPExcel_CachedObjectStorage_SQLite extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
-
38
- /**
39
- * Database table name
40
- *
41
- * @var string
42
- */
43
- private $_TableName = null;
44
-
45
- /**
46
- * Database handle
47
- *
48
- * @var resource
49
- */
50
- private $_DBHandle = null;
51
-
52
- /**
53
- * Store cell data in cache for the current cell object if it's "dirty",
54
- * and the 'nullify' the current cell object
55
- *
56
- * @return void
57
- * @throws PHPExcel_Exception
58
- */
59
- protected function _storeData() {
60
- if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
61
- $this->_currentObject->detach();
62
-
63
- if (!$this->_DBHandle->queryExec("INSERT OR REPLACE INTO kvp_".$this->_TableName." VALUES('".$this->_currentObjectID."','".sqlite_escape_string(serialize($this->_currentObject))."')"))
64
- throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
65
- $this->_currentCellIsDirty = false;
66
- }
67
- $this->_currentObjectID = $this->_currentObject = null;
68
- } // function _storeData()
69
-
70
-
71
- /**
72
- * Add or Update a cell in cache identified by coordinate address
73
- *
74
- * @param string $pCoord Coordinate address of the cell to update
75
- * @param PHPExcel_Cell $cell Cell to update
76
- * @return PHPExcel_Cell
77
- * @throws PHPExcel_Exception
78
- */
79
- public function addCacheData($pCoord, PHPExcel_Cell $cell) {
80
- if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
81
- $this->_storeData();
82
- }
83
-
84
- $this->_currentObjectID = $pCoord;
85
- $this->_currentObject = $cell;
86
- $this->_currentCellIsDirty = true;
87
-
88
- return $cell;
89
- } // function addCacheData()
90
-
91
-
92
- /**
93
- * Get cell at a specific coordinate
94
- *
95
- * @param string $pCoord Coordinate of the cell
96
- * @throws PHPExcel_Exception
97
- * @return PHPExcel_Cell Cell that was found, or null if not found
98
- */
99
- public function getCacheData($pCoord) {
100
- if ($pCoord === $this->_currentObjectID) {
101
- return $this->_currentObject;
102
- }
103
- $this->_storeData();
104
-
105
- $query = "SELECT value FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
106
- $cellResultSet = $this->_DBHandle->query($query,SQLITE_ASSOC);
107
- if ($cellResultSet === false) {
108
- throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
109
- } elseif ($cellResultSet->numRows() == 0) {
110
- // Return null if requested entry doesn't exist in cache
111
- return null;
112
- }
113
-
114
- // Set current entry to the requested entry
115
- $this->_currentObjectID = $pCoord;
116
-
117
- $cellResult = $cellResultSet->fetchSingle();
118
- $this->_currentObject = unserialize($cellResult);
119
- // Re-attach this as the cell's parent
120
- $this->_currentObject->attach($this);
121
-
122
- // Return requested entry
123
- return $this->_currentObject;
124
- } // function getCacheData()
125
-
126
-
127
- /**
128
- * Is a value set for an indexed cell?
129
- *
130
- * @param string $pCoord Coordinate address of the cell to check
131
- * @return boolean
132
- */
133
- public function isDataSet($pCoord) {
134
- if ($pCoord === $this->_currentObjectID) {
135
- return true;
136
- }
137
-
138
- // Check if the requested entry exists in the cache
139
- $query = "SELECT id FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
140
- $cellResultSet = $this->_DBHandle->query($query,SQLITE_ASSOC);
141
- if ($cellResultSet === false) {
142
- throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
143
- } elseif ($cellResultSet->numRows() == 0) {
144
- // Return null if requested entry doesn't exist in cache
145
- return false;
146
- }
147
- return true;
148
- } // function isDataSet()
149
-
150
-
151
- /**
152
- * Delete a cell in cache identified by coordinate address
153
- *
154
- * @param string $pCoord Coordinate address of the cell to delete
155
- * @throws PHPExcel_Exception
156
- */
157
- public function deleteCacheData($pCoord) {
158
- if ($pCoord === $this->_currentObjectID) {
159
- $this->_currentObject->detach();
160
- $this->_currentObjectID = $this->_currentObject = null;
161
- }
162
-
163
- // Check if the requested entry exists in the cache
164
- $query = "DELETE FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
165
- if (!$this->_DBHandle->queryExec($query))
166
- throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
167
-
168
- $this->_currentCellIsDirty = false;
169
- } // function deleteCacheData()
170
-
171
-
172
- /**
173
- * Move a cell object from one address to another
174
- *
175
- * @param string $fromAddress Current address of the cell to move
176
- * @param string $toAddress Destination address of the cell to move
177
- * @return boolean
178
- */
179
- public function moveCell($fromAddress, $toAddress) {
180
- if ($fromAddress === $this->_currentObjectID) {
181
- $this->_currentObjectID = $toAddress;
182
- }
183
-
184
- $query = "DELETE FROM kvp_".$this->_TableName." WHERE id='".$toAddress."'";
185
- $result = $this->_DBHandle->exec($query);
186
- if ($result === false)
187
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
188
-
189
- $query = "UPDATE kvp_".$this->_TableName." SET id='".$toAddress."' WHERE id='".$fromAddress."'";
190
- $result = $this->_DBHandle->exec($query);
191
- if ($result === false)
192
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
193
-
194
- return TRUE;
195
- } // function moveCell()
196
-
197
-
198
- /**
199
- * Get a list of all cell addresses currently held in cache
200
- *
201
- * @return string[]
202
- */
203
- public function getCellList() {
204
- if ($this->_currentObjectID !== null) {
205
- $this->_storeData();
206
- }
207
-
208
- $query = "SELECT id FROM kvp_".$this->_TableName;
209
- $cellIdsResult = $this->_DBHandle->unbufferedQuery($query,SQLITE_ASSOC);
210
- if ($cellIdsResult === false)
211
- throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
212
-
213
- $cellKeys = array();
214
- foreach($cellIdsResult as $row) {
215
- $cellKeys[] = $row['id'];
216
- }
217
-
218
- return $cellKeys;
219
- } // function getCellList()
220
-
221
-
222
- /**
223
- * Clone the cell collection
224
- *
225
- * @param PHPExcel_Worksheet $parent The new worksheet
226
- * @return void
227
- */
228
- public function copyCellCollection(PHPExcel_Worksheet $parent) {
229
- $this->_currentCellIsDirty;
230
- $this->_storeData();
231
-
232
- // Get a new id for the new table name
233
- $tableName = str_replace('.','_',$this->_getUniqueID());
234
- if (!$this->_DBHandle->queryExec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
235
- AS SELECT * FROM kvp_'.$this->_TableName))
236
- throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
237
-
238
- // Copy the existing cell cache file
239
- $this->_TableName = $tableName;
240
- } // function copyCellCollection()
241
-
242
-
243
- /**
244
- * Clear the cell collection and disconnect from our parent
245
- *
246
- * @return void
247
- */
248
- public function unsetWorksheetCells() {
249
- if(!is_null($this->_currentObject)) {
250
- $this->_currentObject->detach();
251
- $this->_currentObject = $this->_currentObjectID = null;
252
- }
253
- // detach ourself from the worksheet, so that it can then delete this object successfully
254
- $this->_parent = null;
255
-
256
- // Close down the temporary cache file
257
- $this->__destruct();
258
- } // function unsetWorksheetCells()
259
-
260
-
261
- /**
262
- * Initialise this new cell collection
263
- *
264
- * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
265
- */
266
- public function __construct(PHPExcel_Worksheet $parent) {
267
- parent::__construct($parent);
268
- if (is_null($this->_DBHandle)) {
269
- $this->_TableName = str_replace('.','_',$this->_getUniqueID());
270
- $_DBName = ':memory:';
271
-
272
- $this->_DBHandle = new SQLiteDatabase($_DBName);
273
- if ($this->_DBHandle === false)
274
- throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
275
- if (!$this->_DBHandle->queryExec('CREATE TABLE kvp_'.$this->_TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)'))
276
- throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
277
- }
278
- } // function __construct()
279
-
280
-
281
- /**
282
- * Destroy this cell collection
283
- */
284
- public function __destruct() {
285
- if (!is_null($this->_DBHandle)) {
286
- $this->_DBHandle->queryExec('DROP TABLE kvp_'.$this->_TableName);
287
- }
288
- $this->_DBHandle = null;
289
- } // function __destruct()
290
-
291
-
292
- /**
293
- * Identify whether the caching method is currently available
294
- * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
295
- *
296
- * @return boolean
297
- */
298
- public static function cacheMethodIsAvailable() {
299
- if (!function_exists('sqlite_open')) {
300
- return false;
301
- }
302
-
303
- return true;
304
- }
305
-
306
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_SQLite
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ class PHPExcel_CachedObjectStorage_SQLite extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
+
38
+ /**
39
+ * Database table name
40
+ *
41
+ * @var string
42
+ */
43
+ private $_TableName = null;
44
+
45
+ /**
46
+ * Database handle
47
+ *
48
+ * @var resource
49
+ */
50
+ private $_DBHandle = null;
51
+
52
+ /**
53
+ * Store cell data in cache for the current cell object if it's "dirty",
54
+ * and the 'nullify' the current cell object
55
+ *
56
+ * @return void
57
+ * @throws PHPExcel_Exception
58
+ */
59
+ protected function _storeData() {
60
+ if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
61
+ $this->_currentObject->detach();
62
+
63
+ if (!$this->_DBHandle->queryExec("INSERT OR REPLACE INTO kvp_".$this->_TableName." VALUES('".$this->_currentObjectID."','".sqlite_escape_string(serialize($this->_currentObject))."')"))
64
+ throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
65
+ $this->_currentCellIsDirty = false;
66
+ }
67
+ $this->_currentObjectID = $this->_currentObject = null;
68
+ } // function _storeData()
69
+
70
+
71
+ /**
72
+ * Add or Update a cell in cache identified by coordinate address
73
+ *
74
+ * @param string $pCoord Coordinate address of the cell to update
75
+ * @param PHPExcel_Cell $cell Cell to update
76
+ * @return PHPExcel_Cell
77
+ * @throws PHPExcel_Exception
78
+ */
79
+ public function addCacheData($pCoord, PHPExcel_Cell $cell) {
80
+ if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
81
+ $this->_storeData();
82
+ }
83
+
84
+ $this->_currentObjectID = $pCoord;
85
+ $this->_currentObject = $cell;
86
+ $this->_currentCellIsDirty = true;
87
+
88
+ return $cell;
89
+ } // function addCacheData()
90
+
91
+
92
+ /**
93
+ * Get cell at a specific coordinate
94
+ *
95
+ * @param string $pCoord Coordinate of the cell
96
+ * @throws PHPExcel_Exception
97
+ * @return PHPExcel_Cell Cell that was found, or null if not found
98
+ */
99
+ public function getCacheData($pCoord) {
100
+ if ($pCoord === $this->_currentObjectID) {
101
+ return $this->_currentObject;
102
+ }
103
+ $this->_storeData();
104
+
105
+ $query = "SELECT value FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
106
+ $cellResultSet = $this->_DBHandle->query($query,SQLITE_ASSOC);
107
+ if ($cellResultSet === false) {
108
+ throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
109
+ } elseif ($cellResultSet->numRows() == 0) {
110
+ // Return null if requested entry doesn't exist in cache
111
+ return null;
112
+ }
113
+
114
+ // Set current entry to the requested entry
115
+ $this->_currentObjectID = $pCoord;
116
+
117
+ $cellResult = $cellResultSet->fetchSingle();
118
+ $this->_currentObject = unserialize($cellResult);
119
+ // Re-attach this as the cell's parent
120
+ $this->_currentObject->attach($this);
121
+
122
+ // Return requested entry
123
+ return $this->_currentObject;
124
+ } // function getCacheData()
125
+
126
+
127
+ /**
128
+ * Is a value set for an indexed cell?
129
+ *
130
+ * @param string $pCoord Coordinate address of the cell to check
131
+ * @return boolean
132
+ */
133
+ public function isDataSet($pCoord) {
134
+ if ($pCoord === $this->_currentObjectID) {
135
+ return true;
136
+ }
137
+
138
+ // Check if the requested entry exists in the cache
139
+ $query = "SELECT id FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
140
+ $cellResultSet = $this->_DBHandle->query($query,SQLITE_ASSOC);
141
+ if ($cellResultSet === false) {
142
+ throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
143
+ } elseif ($cellResultSet->numRows() == 0) {
144
+ // Return null if requested entry doesn't exist in cache
145
+ return false;
146
+ }
147
+ return true;
148
+ } // function isDataSet()
149
+
150
+
151
+ /**
152
+ * Delete a cell in cache identified by coordinate address
153
+ *
154
+ * @param string $pCoord Coordinate address of the cell to delete
155
+ * @throws PHPExcel_Exception
156
+ */
157
+ public function deleteCacheData($pCoord) {
158
+ if ($pCoord === $this->_currentObjectID) {
159
+ $this->_currentObject->detach();
160
+ $this->_currentObjectID = $this->_currentObject = null;
161
+ }
162
+
163
+ // Check if the requested entry exists in the cache
164
+ $query = "DELETE FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
165
+ if (!$this->_DBHandle->queryExec($query))
166
+ throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
167
+
168
+ $this->_currentCellIsDirty = false;
169
+ } // function deleteCacheData()
170
+
171
+
172
+ /**
173
+ * Move a cell object from one address to another
174
+ *
175
+ * @param string $fromAddress Current address of the cell to move
176
+ * @param string $toAddress Destination address of the cell to move
177
+ * @return boolean
178
+ */
179
+ public function moveCell($fromAddress, $toAddress) {
180
+ if ($fromAddress === $this->_currentObjectID) {
181
+ $this->_currentObjectID = $toAddress;
182
+ }
183
+
184
+ $query = "DELETE FROM kvp_".$this->_TableName." WHERE id='".$toAddress."'";
185
+ $result = $this->_DBHandle->exec($query);
186
+ if ($result === false)
187
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
188
+
189
+ $query = "UPDATE kvp_".$this->_TableName." SET id='".$toAddress."' WHERE id='".$fromAddress."'";
190
+ $result = $this->_DBHandle->exec($query);
191
+ if ($result === false)
192
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
193
+
194
+ return TRUE;
195
+ } // function moveCell()
196
+
197
+
198
+ /**
199
+ * Get a list of all cell addresses currently held in cache
200
+ *
201
+ * @return string[]
202
+ */
203
+ public function getCellList() {
204
+ if ($this->_currentObjectID !== null) {
205
+ $this->_storeData();
206
+ }
207
+
208
+ $query = "SELECT id FROM kvp_".$this->_TableName;
209
+ $cellIdsResult = $this->_DBHandle->unbufferedQuery($query,SQLITE_ASSOC);
210
+ if ($cellIdsResult === false)
211
+ throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
212
+
213
+ $cellKeys = array();
214
+ foreach($cellIdsResult as $row) {
215
+ $cellKeys[] = $row['id'];
216
+ }
217
+
218
+ return $cellKeys;
219
+ } // function getCellList()
220
+
221
+
222
+ /**
223
+ * Clone the cell collection
224
+ *
225
+ * @param PHPExcel_Worksheet $parent The new worksheet
226
+ * @return void
227
+ */
228
+ public function copyCellCollection(PHPExcel_Worksheet $parent) {
229
+ $this->_currentCellIsDirty;
230
+ $this->_storeData();
231
+
232
+ // Get a new id for the new table name
233
+ $tableName = str_replace('.','_',$this->_getUniqueID());
234
+ if (!$this->_DBHandle->queryExec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
235
+ AS SELECT * FROM kvp_'.$this->_TableName))
236
+ throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
237
+
238
+ // Copy the existing cell cache file
239
+ $this->_TableName = $tableName;
240
+ } // function copyCellCollection()
241
+
242
+
243
+ /**
244
+ * Clear the cell collection and disconnect from our parent
245
+ *
246
+ * @return void
247
+ */
248
+ public function unsetWorksheetCells() {
249
+ if(!is_null($this->_currentObject)) {
250
+ $this->_currentObject->detach();
251
+ $this->_currentObject = $this->_currentObjectID = null;
252
+ }
253
+ // detach ourself from the worksheet, so that it can then delete this object successfully
254
+ $this->_parent = null;
255
+
256
+ // Close down the temporary cache file
257
+ $this->__destruct();
258
+ } // function unsetWorksheetCells()
259
+
260
+
261
+ /**
262
+ * Initialise this new cell collection
263
+ *
264
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
265
+ */
266
+ public function __construct(PHPExcel_Worksheet $parent) {
267
+ parent::__construct($parent);
268
+ if (is_null($this->_DBHandle)) {
269
+ $this->_TableName = str_replace('.','_',$this->_getUniqueID());
270
+ $_DBName = ':memory:';
271
+
272
+ $this->_DBHandle = new SQLiteDatabase($_DBName);
273
+ if ($this->_DBHandle === false)
274
+ throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
275
+ if (!$this->_DBHandle->queryExec('CREATE TABLE kvp_'.$this->_TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)'))
276
+ throw new PHPExcel_Exception(sqlite_error_string($this->_DBHandle->lastError()));
277
+ }
278
+ } // function __construct()
279
+
280
+
281
+ /**
282
+ * Destroy this cell collection
283
+ */
284
+ public function __destruct() {
285
+ if (!is_null($this->_DBHandle)) {
286
+ $this->_DBHandle->queryExec('DROP TABLE kvp_'.$this->_TableName);
287
+ }
288
+ $this->_DBHandle = null;
289
+ } // function __destruct()
290
+
291
+
292
+ /**
293
+ * Identify whether the caching method is currently available
294
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
295
+ *
296
+ * @return boolean
297
+ */
298
+ public static function cacheMethodIsAvailable() {
299
+ if (!function_exists('sqlite_open')) {
300
+ return false;
301
+ }
302
+
303
+ return true;
304
+ }
305
+
306
+ }
{libraries → classes}/PHPExcel/CachedObjectStorage/SQLite3.php RENAMED
@@ -1,345 +1,345 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_SQLite3
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
-
38
- /**
39
- * Database table name
40
- *
41
- * @var string
42
- */
43
- private $_TableName = null;
44
-
45
- /**
46
- * Database handle
47
- *
48
- * @var resource
49
- */
50
- private $_DBHandle = null;
51
-
52
- /**
53
- * Prepared statement for a SQLite3 select query
54
- *
55
- * @var SQLite3Stmt
56
- */
57
- private $_selectQuery;
58
-
59
- /**
60
- * Prepared statement for a SQLite3 insert query
61
- *
62
- * @var SQLite3Stmt
63
- */
64
- private $_insertQuery;
65
-
66
- /**
67
- * Prepared statement for a SQLite3 update query
68
- *
69
- * @var SQLite3Stmt
70
- */
71
- private $_updateQuery;
72
-
73
- /**
74
- * Prepared statement for a SQLite3 delete query
75
- *
76
- * @var SQLite3Stmt
77
- */
78
- private $_deleteQuery;
79
-
80
- /**
81
- * Store cell data in cache for the current cell object if it's "dirty",
82
- * and the 'nullify' the current cell object
83
- *
84
- * @return void
85
- * @throws PHPExcel_Exception
86
- */
87
- protected function _storeData() {
88
- if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
89
- $this->_currentObject->detach();
90
-
91
- $this->_insertQuery->bindValue('id',$this->_currentObjectID,SQLITE3_TEXT);
92
- $this->_insertQuery->bindValue('data',serialize($this->_currentObject),SQLITE3_BLOB);
93
- $result = $this->_insertQuery->execute();
94
- if ($result === false)
95
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
96
- $this->_currentCellIsDirty = false;
97
- }
98
- $this->_currentObjectID = $this->_currentObject = null;
99
- } // function _storeData()
100
-
101
-
102
- /**
103
- * Add or Update a cell in cache identified by coordinate address
104
- *
105
- * @param string $pCoord Coordinate address of the cell to update
106
- * @param PHPExcel_Cell $cell Cell to update
107
- * @return PHPExcel_Cell
108
- * @throws PHPExcel_Exception
109
- */
110
- public function addCacheData($pCoord, PHPExcel_Cell $cell) {
111
- if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
112
- $this->_storeData();
113
- }
114
-
115
- $this->_currentObjectID = $pCoord;
116
- $this->_currentObject = $cell;
117
- $this->_currentCellIsDirty = true;
118
-
119
- return $cell;
120
- } // function addCacheData()
121
-
122
-
123
- /**
124
- * Get cell at a specific coordinate
125
- *
126
- * @param string $pCoord Coordinate of the cell
127
- * @throws PHPExcel_Exception
128
- * @return PHPExcel_Cell Cell that was found, or null if not found
129
- */
130
- public function getCacheData($pCoord) {
131
- if ($pCoord === $this->_currentObjectID) {
132
- return $this->_currentObject;
133
- }
134
- $this->_storeData();
135
-
136
- $this->_selectQuery->bindValue('id',$pCoord,SQLITE3_TEXT);
137
- $cellResult = $this->_selectQuery->execute();
138
- if ($cellResult === FALSE) {
139
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
140
- }
141
- $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
142
- if ($cellData === FALSE) {
143
- // Return null if requested entry doesn't exist in cache
144
- return NULL;
145
- }
146
-
147
- // Set current entry to the requested entry
148
- $this->_currentObjectID = $pCoord;
149
-
150
- $this->_currentObject = unserialize($cellData['value']);
151
- // Re-attach this as the cell's parent
152
- $this->_currentObject->attach($this);
153
-
154
- // Return requested entry
155
- return $this->_currentObject;
156
- } // function getCacheData()
157
-
158
-
159
- /**
160
- * Is a value set for an indexed cell?
161
- *
162
- * @param string $pCoord Coordinate address of the cell to check
163
- * @return boolean
164
- */
165
- public function isDataSet($pCoord) {
166
- if ($pCoord === $this->_currentObjectID) {
167
- return TRUE;
168
- }
169
-
170
- // Check if the requested entry exists in the cache
171
- $this->_selectQuery->bindValue('id',$pCoord,SQLITE3_TEXT);
172
- $cellResult = $this->_selectQuery->execute();
173
- if ($cellResult === FALSE) {
174
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
175
- }
176
- $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
177
-
178
- return ($cellData === FALSE) ? FALSE : TRUE;
179
- } // function isDataSet()
180
-
181
-
182
- /**
183
- * Delete a cell in cache identified by coordinate address
184
- *
185
- * @param string $pCoord Coordinate address of the cell to delete
186
- * @throws PHPExcel_Exception
187
- */
188
- public function deleteCacheData($pCoord) {
189
- if ($pCoord === $this->_currentObjectID) {
190
- $this->_currentObject->detach();
191
- $this->_currentObjectID = $this->_currentObject = NULL;
192
- }
193
-
194
- // Check if the requested entry exists in the cache
195
- $this->_deleteQuery->bindValue('id',$pCoord,SQLITE3_TEXT);
196
- $result = $this->_deleteQuery->execute();
197
- if ($result === FALSE)
198
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
199
-
200
- $this->_currentCellIsDirty = FALSE;
201
- } // function deleteCacheData()
202
-
203
-
204
- /**
205
- * Move a cell object from one address to another
206
- *
207
- * @param string $fromAddress Current address of the cell to move
208
- * @param string $toAddress Destination address of the cell to move
209
- * @return boolean
210
- */
211
- public function moveCell($fromAddress, $toAddress) {
212
- if ($fromAddress === $this->_currentObjectID) {
213
- $this->_currentObjectID = $toAddress;
214
- }
215
-
216
- $this->_deleteQuery->bindValue('id',$toAddress,SQLITE3_TEXT);
217
- $result = $this->_deleteQuery->execute();
218
- if ($result === false)
219
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
220
-
221
- $this->_updateQuery->bindValue('toid',$toAddress,SQLITE3_TEXT);
222
- $this->_updateQuery->bindValue('fromid',$fromAddress,SQLITE3_TEXT);
223
- $result = $this->_updateQuery->execute();
224
- if ($result === false)
225
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
226
-
227
- return TRUE;
228
- } // function moveCell()
229
-
230
-
231
- /**
232
- * Get a list of all cell addresses currently held in cache
233
- *
234
- * @return string[]
235
- */
236
- public function getCellList() {
237
- if ($this->_currentObjectID !== null) {
238
- $this->_storeData();
239
- }
240
-
241
- $query = "SELECT id FROM kvp_".$this->_TableName;
242
- $cellIdsResult = $this->_DBHandle->query($query);
243
- if ($cellIdsResult === false)
244
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
245
-
246
- $cellKeys = array();
247
- while ($row = $cellIdsResult->fetchArray(SQLITE3_ASSOC)) {
248
- $cellKeys[] = $row['id'];
249
- }
250
-
251
- return $cellKeys;
252
- } // function getCellList()
253
-
254
-
255
- /**
256
- * Clone the cell collection
257
- *
258
- * @param PHPExcel_Worksheet $parent The new worksheet
259
- * @return void
260
- */
261
- public function copyCellCollection(PHPExcel_Worksheet $parent) {
262
- $this->_currentCellIsDirty;
263
- $this->_storeData();
264
-
265
- // Get a new id for the new table name
266
- $tableName = str_replace('.','_',$this->_getUniqueID());
267
- if (!$this->_DBHandle->exec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
268
- AS SELECT * FROM kvp_'.$this->_TableName))
269
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
270
-
271
- // Copy the existing cell cache file
272
- $this->_TableName = $tableName;
273
- } // function copyCellCollection()
274
-
275
-
276
- /**
277
- * Clear the cell collection and disconnect from our parent
278
- *
279
- * @return void
280
- */
281
- public function unsetWorksheetCells() {
282
- if(!is_null($this->_currentObject)) {
283
- $this->_currentObject->detach();
284
- $this->_currentObject = $this->_currentObjectID = null;
285
- }
286
- // detach ourself from the worksheet, so that it can then delete this object successfully
287
- $this->_parent = null;
288
-
289
- // Close down the temporary cache file
290
- $this->__destruct();
291
- } // function unsetWorksheetCells()
292
-
293
-
294
- /**
295
- * Initialise this new cell collection
296
- *
297
- * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
298
- */
299
- public function __construct(PHPExcel_Worksheet $parent) {
300
- parent::__construct($parent);
301
- if (is_null($this->_DBHandle)) {
302
- $this->_TableName = str_replace('.','_',$this->_getUniqueID());
303
- $_DBName = ':memory:';
304
-
305
- $this->_DBHandle = new SQLite3($_DBName);
306
- if ($this->_DBHandle === false)
307
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
308
- if (!$this->_DBHandle->exec('CREATE TABLE kvp_'.$this->_TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)'))
309
- throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
310
- }
311
-
312
- $this->_selectQuery = $this->_DBHandle->prepare("SELECT value FROM kvp_".$this->_TableName." WHERE id = :id");
313
- $this->_insertQuery = $this->_DBHandle->prepare("INSERT OR REPLACE INTO kvp_".$this->_TableName." VALUES(:id,:data)");
314
- $this->_updateQuery = $this->_DBHandle->prepare("UPDATE kvp_".$this->_TableName." SET id=:toId WHERE id=:fromId");
315
- $this->_deleteQuery = $this->_DBHandle->prepare("DELETE FROM kvp_".$this->_TableName." WHERE id = :id");
316
- } // function __construct()
317
-
318
-
319
- /**
320
- * Destroy this cell collection
321
- */
322
- public function __destruct() {
323
- if (!is_null($this->_DBHandle)) {
324
- $this->_DBHandle->exec('DROP TABLE kvp_'.$this->_TableName);
325
- $this->_DBHandle->close();
326
- }
327
- $this->_DBHandle = null;
328
- } // function __destruct()
329
-
330
-
331
- /**
332
- * Identify whether the caching method is currently available
333
- * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
334
- *
335
- * @return boolean
336
- */
337
- public static function cacheMethodIsAvailable() {
338
- if (!class_exists('SQLite3',FALSE)) {
339
- return false;
340
- }
341
-
342
- return true;
343
- }
344
-
345
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_SQLite3
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
+
38
+ /**
39
+ * Database table name
40
+ *
41
+ * @var string
42
+ */
43
+ private $_TableName = null;
44
+
45
+ /**
46
+ * Database handle
47
+ *
48
+ * @var resource
49
+ */
50
+ private $_DBHandle = null;
51
+
52
+ /**
53
+ * Prepared statement for a SQLite3 select query
54
+ *
55
+ * @var SQLite3Stmt
56
+ */
57
+ private $_selectQuery;
58
+
59
+ /**
60
+ * Prepared statement for a SQLite3 insert query
61
+ *
62
+ * @var SQLite3Stmt
63
+ */
64
+ private $_insertQuery;
65
+
66
+ /**
67
+ * Prepared statement for a SQLite3 update query
68
+ *
69
+ * @var SQLite3Stmt
70
+ */
71
+ private $_updateQuery;
72
+
73
+ /**
74
+ * Prepared statement for a SQLite3 delete query
75
+ *
76
+ * @var SQLite3Stmt
77
+ */
78
+ private $_deleteQuery;
79
+
80
+ /**
81
+ * Store cell data in cache for the current cell object if it's "dirty",
82
+ * and the 'nullify' the current cell object
83
+ *
84
+ * @return void
85
+ * @throws PHPExcel_Exception
86
+ */
87
+ protected function _storeData() {
88
+ if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
89
+ $this->_currentObject->detach();
90
+
91
+ $this->_insertQuery->bindValue('id',$this->_currentObjectID,SQLITE3_TEXT);
92
+ $this->_insertQuery->bindValue('data',serialize($this->_currentObject),SQLITE3_BLOB);
93
+ $result = $this->_insertQuery->execute();
94
+ if ($result === false)
95
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
96
+ $this->_currentCellIsDirty = false;
97
+ }
98
+ $this->_currentObjectID = $this->_currentObject = null;
99
+ } // function _storeData()
100
+
101
+
102
+ /**
103
+ * Add or Update a cell in cache identified by coordinate address
104
+ *
105
+ * @param string $pCoord Coordinate address of the cell to update
106
+ * @param PHPExcel_Cell $cell Cell to update
107
+ * @return PHPExcel_Cell
108
+ * @throws PHPExcel_Exception
109
+ */
110
+ public function addCacheData($pCoord, PHPExcel_Cell $cell) {
111
+ if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
112
+ $this->_storeData();
113
+ }
114
+
115
+ $this->_currentObjectID = $pCoord;
116
+ $this->_currentObject = $cell;
117
+ $this->_currentCellIsDirty = true;
118
+
119
+ return $cell;
120
+ } // function addCacheData()
121
+
122
+
123
+ /**
124
+ * Get cell at a specific coordinate
125
+ *
126
+ * @param string $pCoord Coordinate of the cell
127
+ * @throws PHPExcel_Exception
128
+ * @return PHPExcel_Cell Cell that was found, or null if not found
129
+ */
130
+ public function getCacheData($pCoord) {
131
+ if ($pCoord === $this->_currentObjectID) {
132
+ return $this->_currentObject;
133
+ }
134
+ $this->_storeData();
135
+
136
+ $this->_selectQuery->bindValue('id',$pCoord,SQLITE3_TEXT);
137
+ $cellResult = $this->_selectQuery->execute();
138
+ if ($cellResult === FALSE) {
139
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
140
+ }
141
+ $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
142
+ if ($cellData === FALSE) {
143
+ // Return null if requested entry doesn't exist in cache
144
+ return NULL;
145
+ }
146
+
147
+ // Set current entry to the requested entry
148
+ $this->_currentObjectID = $pCoord;
149
+
150
+ $this->_currentObject = unserialize($cellData['value']);
151
+ // Re-attach this as the cell's parent
152
+ $this->_currentObject->attach($this);
153
+
154
+ // Return requested entry
155
+ return $this->_currentObject;
156
+ } // function getCacheData()
157
+
158
+
159
+ /**
160
+ * Is a value set for an indexed cell?
161
+ *
162
+ * @param string $pCoord Coordinate address of the cell to check
163
+ * @return boolean
164
+ */
165
+ public function isDataSet($pCoord) {
166
+ if ($pCoord === $this->_currentObjectID) {
167
+ return TRUE;
168
+ }
169
+
170
+ // Check if the requested entry exists in the cache
171
+ $this->_selectQuery->bindValue('id',$pCoord,SQLITE3_TEXT);
172
+ $cellResult = $this->_selectQuery->execute();
173
+ if ($cellResult === FALSE) {
174
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
175
+ }
176
+ $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
177
+
178
+ return ($cellData === FALSE) ? FALSE : TRUE;
179
+ } // function isDataSet()
180
+
181
+
182
+ /**
183
+ * Delete a cell in cache identified by coordinate address
184
+ *
185
+ * @param string $pCoord Coordinate address of the cell to delete
186
+ * @throws PHPExcel_Exception
187
+ */
188
+ public function deleteCacheData($pCoord) {
189
+ if ($pCoord === $this->_currentObjectID) {
190
+ $this->_currentObject->detach();
191
+ $this->_currentObjectID = $this->_currentObject = NULL;
192
+ }
193
+
194
+ // Check if the requested entry exists in the cache
195
+ $this->_deleteQuery->bindValue('id',$pCoord,SQLITE3_TEXT);
196
+ $result = $this->_deleteQuery->execute();
197
+ if ($result === FALSE)
198
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
199
+
200
+ $this->_currentCellIsDirty = FALSE;
201
+ } // function deleteCacheData()
202
+
203
+
204
+ /**
205
+ * Move a cell object from one address to another
206
+ *
207
+ * @param string $fromAddress Current address of the cell to move
208
+ * @param string $toAddress Destination address of the cell to move
209
+ * @return boolean
210
+ */
211
+ public function moveCell($fromAddress, $toAddress) {
212
+ if ($fromAddress === $this->_currentObjectID) {
213
+ $this->_currentObjectID = $toAddress;
214
+ }
215
+
216
+ $this->_deleteQuery->bindValue('id',$toAddress,SQLITE3_TEXT);
217
+ $result = $this->_deleteQuery->execute();
218
+ if ($result === false)
219
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
220
+
221
+ $this->_updateQuery->bindValue('toid',$toAddress,SQLITE3_TEXT);
222
+ $this->_updateQuery->bindValue('fromid',$fromAddress,SQLITE3_TEXT);
223
+ $result = $this->_updateQuery->execute();
224
+ if ($result === false)
225
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
226
+
227
+ return TRUE;
228
+ } // function moveCell()
229
+
230
+
231
+ /**
232
+ * Get a list of all cell addresses currently held in cache
233
+ *
234
+ * @return string[]
235
+ */
236
+ public function getCellList() {
237
+ if ($this->_currentObjectID !== null) {
238
+ $this->_storeData();
239
+ }
240
+
241
+ $query = "SELECT id FROM kvp_".$this->_TableName;
242
+ $cellIdsResult = $this->_DBHandle->query($query);
243
+ if ($cellIdsResult === false)
244
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
245
+
246
+ $cellKeys = array();
247
+ while ($row = $cellIdsResult->fetchArray(SQLITE3_ASSOC)) {
248
+ $cellKeys[] = $row['id'];
249
+ }
250
+
251
+ return $cellKeys;
252
+ } // function getCellList()
253
+
254
+
255
+ /**
256
+ * Clone the cell collection
257
+ *
258
+ * @param PHPExcel_Worksheet $parent The new worksheet
259
+ * @return void
260
+ */
261
+ public function copyCellCollection(PHPExcel_Worksheet $parent) {
262
+ $this->_currentCellIsDirty;
263
+ $this->_storeData();
264
+
265
+ // Get a new id for the new table name
266
+ $tableName = str_replace('.','_',$this->_getUniqueID());
267
+ if (!$this->_DBHandle->exec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
268
+ AS SELECT * FROM kvp_'.$this->_TableName))
269
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
270
+
271
+ // Copy the existing cell cache file
272
+ $this->_TableName = $tableName;
273
+ } // function copyCellCollection()
274
+
275
+
276
+ /**
277
+ * Clear the cell collection and disconnect from our parent
278
+ *
279
+ * @return void
280
+ */
281
+ public function unsetWorksheetCells() {
282
+ if(!is_null($this->_currentObject)) {
283
+ $this->_currentObject->detach();
284
+ $this->_currentObject = $this->_currentObjectID = null;
285
+ }
286
+ // detach ourself from the worksheet, so that it can then delete this object successfully
287
+ $this->_parent = null;
288
+
289
+ // Close down the temporary cache file
290
+ $this->__destruct();
291
+ } // function unsetWorksheetCells()
292
+
293
+
294
+ /**
295
+ * Initialise this new cell collection
296
+ *
297
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
298
+ */
299
+ public function __construct(PHPExcel_Worksheet $parent) {
300
+ parent::__construct($parent);
301
+ if (is_null($this->_DBHandle)) {
302
+ $this->_TableName = str_replace('.','_',$this->_getUniqueID());
303
+ $_DBName = ':memory:';
304
+
305
+ $this->_DBHandle = new SQLite3($_DBName);
306
+ if ($this->_DBHandle === false)
307
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
308
+ if (!$this->_DBHandle->exec('CREATE TABLE kvp_'.$this->_TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)'))
309
+ throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg());
310
+ }
311
+
312
+ $this->_selectQuery = $this->_DBHandle->prepare("SELECT value FROM kvp_".$this->_TableName." WHERE id = :id");
313
+ $this->_insertQuery = $this->_DBHandle->prepare("INSERT OR REPLACE INTO kvp_".$this->_TableName." VALUES(:id,:data)");
314
+ $this->_updateQuery = $this->_DBHandle->prepare("UPDATE kvp_".$this->_TableName." SET id=:toId WHERE id=:fromId");
315
+ $this->_deleteQuery = $this->_DBHandle->prepare("DELETE FROM kvp_".$this->_TableName." WHERE id = :id");
316
+ } // function __construct()
317
+
318
+
319
+ /**
320
+ * Destroy this cell collection
321
+ */
322
+ public function __destruct() {
323
+ if (!is_null($this->_DBHandle)) {
324
+ $this->_DBHandle->exec('DROP TABLE kvp_'.$this->_TableName);
325
+ $this->_DBHandle->close();
326
+ }
327
+ $this->_DBHandle = null;
328
+ } // function __destruct()
329
+
330
+
331
+ /**
332
+ * Identify whether the caching method is currently available
333
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
334
+ *
335
+ * @return boolean
336
+ */
337
+ public static function cacheMethodIsAvailable() {
338
+ if (!class_exists('SQLite3',FALSE)) {
339
+ return false;
340
+ }
341
+
342
+ return true;
343
+ }
344
+
345
+ }
{libraries → classes}/PHPExcel/CachedObjectStorage/Wincache.php RENAMED
@@ -1,294 +1,294 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_CachedObjectStorage
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
-
29
- /**
30
- * PHPExcel_CachedObjectStorage_Wincache
31
- *
32
- * @category PHPExcel
33
- * @package PHPExcel_CachedObjectStorage
34
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
- */
36
- class PHPExcel_CachedObjectStorage_Wincache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
-
38
- /**
39
- * Prefix used to uniquely identify cache data for this worksheet
40
- *
41
- * @var string
42
- */
43
- private $_cachePrefix = null;
44
-
45
- /**
46
- * Cache timeout
47
- *
48
- * @var integer
49
- */
50
- private $_cacheTime = 600;
51
-
52
-
53
- /**
54
- * Store cell data in cache for the current cell object if it's "dirty",
55
- * and the 'nullify' the current cell object
56
- *
57
- * @return void
58
- * @throws PHPExcel_Exception
59
- */
60
- protected function _storeData() {
61
- if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
62
- $this->_currentObject->detach();
63
-
64
- $obj = serialize($this->_currentObject);
65
- if (wincache_ucache_exists($this->_cachePrefix.$this->_currentObjectID.'.cache')) {
66
- if (!wincache_ucache_set($this->_cachePrefix.$this->_currentObjectID.'.cache', $obj, $this->_cacheTime)) {
67
- $this->__destruct();
68
- throw new PHPExcel_Exception('Failed to store cell '.$this->_currentObjectID.' in WinCache');
69
- }
70
- } else {
71
- if (!wincache_ucache_add($this->_cachePrefix.$this->_currentObjectID.'.cache', $obj, $this->_cacheTime)) {
72
- $this->__destruct();
73
- throw new PHPExcel_Exception('Failed to store cell '.$this->_currentObjectID.' in WinCache');
74
- }
75
- }
76
- $this->_currentCellIsDirty = false;
77
- }
78
-
79
- $this->_currentObjectID = $this->_currentObject = null;
80
- } // function _storeData()
81
-
82
-
83
- /**
84
- * Add or Update a cell in cache identified by coordinate address
85
- *
86
- * @param string $pCoord Coordinate address of the cell to update
87
- * @param PHPExcel_Cell $cell Cell to update
88
- * @return PHPExcel_Cell
89
- * @throws PHPExcel_Exception
90
- */
91
- public function addCacheData($pCoord, PHPExcel_Cell $cell) {
92
- if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
93
- $this->_storeData();
94
- }
95
- $this->_cellCache[$pCoord] = true;
96
-
97
- $this->_currentObjectID = $pCoord;
98
- $this->_currentObject = $cell;
99
- $this->_currentCellIsDirty = true;
100
-
101
- return $cell;
102
- } // function addCacheData()
103
-
104
-
105
- /**
106
- * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
107
- *
108
- * @param string $pCoord Coordinate address of the cell to check
109
- * @return boolean
110
- */
111
- public function isDataSet($pCoord) {
112
- // Check if the requested entry is the current object, or exists in the cache
113
- if (parent::isDataSet($pCoord)) {
114
- if ($this->_currentObjectID == $pCoord) {
115
- return true;
116
- }
117
- // Check if the requested entry still exists in cache
118
- $success = wincache_ucache_exists($this->_cachePrefix.$pCoord.'.cache');
119
- if ($success === false) {
120
- // Entry no longer exists in Wincache, so clear it from the cache array
121
- parent::deleteCacheData($pCoord);
122
- throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in WinCache');
123
- }
124
- return true;
125
- }
126
- return false;
127
- } // function isDataSet()
128
-
129
-
130
- /**
131
- * Get cell at a specific coordinate
132
- *
133
- * @param string $pCoord Coordinate of the cell
134
- * @throws PHPExcel_Exception
135
- * @return PHPExcel_Cell Cell that was found, or null if not found
136
- */
137
- public function getCacheData($pCoord) {
138
- if ($pCoord === $this->_currentObjectID) {
139
- return $this->_currentObject;
140
- }
141
- $this->_storeData();
142
-
143
- // Check if the entry that has been requested actually exists
144
- $obj = null;
145
- if (parent::isDataSet($pCoord)) {
146
- $success = false;
147
- $obj = wincache_ucache_get($this->_cachePrefix.$pCoord.'.cache', $success);
148
- if ($success === false) {
149
- // Entry no longer exists in WinCache, so clear it from the cache array
150
- parent::deleteCacheData($pCoord);
151
- throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in WinCache');
152
- }
153
- } else {
154
- // Return null if requested entry doesn't exist in cache
155
- return null;
156
- }
157
-
158
- // Set current entry to the requested entry
159
- $this->_currentObjectID = $pCoord;
160
- $this->_currentObject = unserialize($obj);
161
- // Re-attach this as the cell's parent
162
- $this->_currentObject->attach($this);
163
-
164
- // Return requested entry
165
- return $this->_currentObject;
166
- } // function getCacheData()
167
-
168
-
169
- /**
170
- * Get a list of all cell addresses currently held in cache
171
- *
172
- * @return string[]
173
- */
174
- public function getCellList() {
175
- if ($this->_currentObjectID !== null) {
176
- $this->_storeData();
177
- }
178
-
179
- return parent::getCellList();
180
- }
181
-
182
-
183
- /**
184
- * Delete a cell in cache identified by coordinate address
185
- *
186
- * @param string $pCoord Coordinate address of the cell to delete
187
- * @throws PHPExcel_Exception
188
- */
189
- public function deleteCacheData($pCoord) {
190
- // Delete the entry from Wincache
191
- wincache_ucache_delete($this->_cachePrefix.$pCoord.'.cache');
192
-
193
- // Delete the entry from our cell address array
194
- parent::deleteCacheData($pCoord);
195
- } // function deleteCacheData()
196
-
197
-
198
- /**
199
- * Clone the cell collection
200
- *
201
- * @param PHPExcel_Worksheet $parent The new worksheet
202
- * @return void
203
- */
204
- public function copyCellCollection(PHPExcel_Worksheet $parent) {
205
- parent::copyCellCollection($parent);
206
- // Get a new id for the new file name
207
- $baseUnique = $this->_getUniqueID();
208
- $newCachePrefix = substr(md5($baseUnique),0,8).'.';
209
- $cacheList = $this->getCellList();
210
- foreach($cacheList as $cellID) {
211
- if ($cellID != $this->_currentObjectID) {
212
- $success = false;
213
- $obj = wincache_ucache_get($this->_cachePrefix.$cellID.'.cache', $success);
214
- if ($success === false) {
215
- // Entry no longer exists in WinCache, so clear it from the cache array
216
- parent::deleteCacheData($cellID);
217
- throw new PHPExcel_Exception('Cell entry '.$cellID.' no longer exists in Wincache');
218
- }
219
- if (!wincache_ucache_add($newCachePrefix.$cellID.'.cache', $obj, $this->_cacheTime)) {
220
- $this->__destruct();
221
- throw new PHPExcel_Exception('Failed to store cell '.$cellID.' in Wincache');
222
- }
223
- }
224
- }
225
- $this->_cachePrefix = $newCachePrefix;
226
- } // function copyCellCollection()
227
-
228
-
229
- /**
230
- * Clear the cell collection and disconnect from our parent
231
- *
232
- * @return void
233
- */
234
- public function unsetWorksheetCells() {
235
- if(!is_null($this->_currentObject)) {
236
- $this->_currentObject->detach();
237
- $this->_currentObject = $this->_currentObjectID = null;
238
- }
239
-
240
- // Flush the WinCache cache
241
- $this->__destruct();
242
-
243
- $this->_cellCache = array();
244
-
245
- // detach ourself from the worksheet, so that it can then delete this object successfully
246
- $this->_parent = null;
247
- } // function unsetWorksheetCells()
248
-
249
-
250
- /**
251
- * Initialise this new cell collection
252
- *
253
- * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
254
- * @param array of mixed $arguments Additional initialisation arguments
255
- */
256
- public function __construct(PHPExcel_Worksheet $parent, $arguments) {
257
- $cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600;
258
-
259
- if (is_null($this->_cachePrefix)) {
260
- $baseUnique = $this->_getUniqueID();
261
- $this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
262
- $this->_cacheTime = $cacheTime;
263
-
264
- parent::__construct($parent);
265
- }
266
- } // function __construct()
267
-
268
-
269
- /**
270
- * Destroy this cell collection
271
- */
272
- public function __destruct() {
273
- $cacheList = $this->getCellList();
274
- foreach($cacheList as $cellID) {
275
- wincache_ucache_delete($this->_cachePrefix.$cellID.'.cache');
276
- }
277
- } // function __destruct()
278
-
279
-
280
- /**
281
- * Identify whether the caching method is currently available
282
- * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
283
- *
284
- * @return boolean
285
- */
286
- public static function cacheMethodIsAvailable() {
287
- if (!function_exists('wincache_ucache_add')) {
288
- return false;
289
- }
290
-
291
- return true;
292
- }
293
-
294
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_CachedObjectStorage
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+
29
+ /**
30
+ * PHPExcel_CachedObjectStorage_Wincache
31
+ *
32
+ * @category PHPExcel
33
+ * @package PHPExcel_CachedObjectStorage
34
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35
+ */
36
+ class PHPExcel_CachedObjectStorage_Wincache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37
+
38
+ /**
39
+ * Prefix used to uniquely identify cache data for this worksheet
40
+ *
41
+ * @var string
42
+ */
43
+ private $_cachePrefix = null;
44
+
45
+ /**
46
+ * Cache timeout
47
+ *
48
+ * @var integer
49
+ */
50
+ private $_cacheTime = 600;
51
+
52
+
53
+ /**
54
+ * Store cell data in cache for the current cell object if it's "dirty",
55
+ * and the 'nullify' the current cell object
56
+ *
57
+ * @return void
58
+ * @throws PHPExcel_Exception
59
+ */
60
+ protected function _storeData() {
61
+ if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
62
+ $this->_currentObject->detach();
63
+
64
+ $obj = serialize($this->_currentObject);
65
+ if (wincache_ucache_exists($this->_cachePrefix.$this->_currentObjectID.'.cache')) {
66
+ if (!wincache_ucache_set($this->_cachePrefix.$this->_currentObjectID.'.cache', $obj, $this->_cacheTime)) {
67
+ $this->__destruct();
68
+ throw new PHPExcel_Exception('Failed to store cell '.$this->_currentObjectID.' in WinCache');
69
+ }
70
+ } else {
71
+ if (!wincache_ucache_add($this->_cachePrefix.$this->_currentObjectID.'.cache', $obj, $this->_cacheTime)) {
72
+ $this->__destruct();
73
+ throw new PHPExcel_Exception('Failed to store cell '.$this->_currentObjectID.' in WinCache');
74
+ }
75
+ }
76
+ $this->_currentCellIsDirty = false;
77
+ }
78
+
79
+ $this->_currentObjectID = $this->_currentObject = null;
80
+ } // function _storeData()
81
+
82
+
83
+ /**
84
+ * Add or Update a cell in cache identified by coordinate address
85
+ *
86
+ * @param string $pCoord Coordinate address of the cell to update
87
+ * @param PHPExcel_Cell $cell Cell to update
88
+ * @return PHPExcel_Cell
89
+ * @throws PHPExcel_Exception
90
+ */
91
+ public function addCacheData($pCoord, PHPExcel_Cell $cell) {
92
+ if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
93
+ $this->_storeData();
94
+ }
95
+ $this->_cellCache[$pCoord] = true;
96
+
97
+ $this->_currentObjectID = $pCoord;
98
+ $this->_currentObject = $cell;
99
+ $this->_currentCellIsDirty = true;
100
+
101
+ return $cell;
102
+ } // function addCacheData()
103
+
104
+
105
+ /**
106
+ * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
107
+ *
108
+ * @param string $pCoord Coordinate address of the cell to check
109
+ * @return boolean
110
+ */
111
+ public function isDataSet($pCoord) {
112
+ // Check if the requested entry is the current object, or exists in the cache
113
+ if (parent::isDataSet($pCoord)) {
114
+ if ($this->_currentObjectID == $pCoord) {
115
+ return true;
116
+ }
117
+ // Check if the requested entry still exists in cache
118
+ $success = wincache_ucache_exists($this->_cachePrefix.$pCoord.'.cache');
119
+ if ($success === false) {
120
+ // Entry no longer exists in Wincache, so clear it from the cache array
121
+ parent::deleteCacheData($pCoord);
122
+ throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in WinCache');
123
+ }
124
+ return true;
125
+ }
126
+ return false;
127
+ } // function isDataSet()
128
+
129
+
130
+ /**
131
+ * Get cell at a specific coordinate
132
+ *
133
+ * @param string $pCoord Coordinate of the cell
134
+ * @throws PHPExcel_Exception
135
+ * @return PHPExcel_Cell Cell that was found, or null if not found
136
+ */
137
+ public function getCacheData($pCoord) {
138
+ if ($pCoord === $this->_currentObjectID) {
139
+ return $this->_currentObject;
140
+ }
141
+ $this->_storeData();
142
+
143
+ // Check if the entry that has been requested actually exists
144
+ $obj = null;
145
+ if (parent::isDataSet($pCoord)) {
146
+ $success = false;
147
+ $obj = wincache_ucache_get($this->_cachePrefix.$pCoord.'.cache', $success);
148
+ if ($success === false) {
149
+ // Entry no longer exists in WinCache, so clear it from the cache array
150
+ parent::deleteCacheData($pCoord);
151
+ throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in WinCache');
152
+ }
153
+ } else {
154
+ // Return null if requested entry doesn't exist in cache
155
+ return null;
156
+ }
157
+
158
+ // Set current entry to the requested entry
159
+ $this->_currentObjectID = $pCoord;
160
+ $this->_currentObject = unserialize($obj);
161
+ // Re-attach this as the cell's parent
162
+ $this->_currentObject->attach($this);
163
+
164
+ // Return requested entry
165
+ return $this->_currentObject;
166
+ } // function getCacheData()
167
+
168
+
169
+ /**
170
+ * Get a list of all cell addresses currently held in cache
171
+ *
172
+ * @return string[]
173
+ */
174
+ public function getCellList() {
175
+ if ($this->_currentObjectID !== null) {
176
+ $this->_storeData();
177
+ }
178
+
179
+ return parent::getCellList();
180
+ }
181
+
182
+
183
+ /**
184
+ * Delete a cell in cache identified by coordinate address
185
+ *
186
+ * @param string $pCoord Coordinate address of the cell to delete
187
+ * @throws PHPExcel_Exception
188
+ */
189
+ public function deleteCacheData($pCoord) {
190
+ // Delete the entry from Wincache
191
+ wincache_ucache_delete($this->_cachePrefix.$pCoord.'.cache');
192
+
193
+ // Delete the entry from our cell address array
194
+ parent::deleteCacheData($pCoord);
195
+ } // function deleteCacheData()
196
+
197
+
198
+ /**
199
+ * Clone the cell collection
200
+ *
201
+ * @param PHPExcel_Worksheet $parent The new worksheet
202
+ * @return void
203
+ */
204
+ public function copyCellCollection(PHPExcel_Worksheet $parent) {
205
+ parent::copyCellCollection($parent);
206
+ // Get a new id for the new file name
207
+ $baseUnique = $this->_getUniqueID();
208
+ $newCachePrefix = substr(md5($baseUnique),0,8).'.';
209
+ $cacheList = $this->getCellList();
210
+ foreach($cacheList as $cellID) {
211
+ if ($cellID != $this->_currentObjectID) {
212
+ $success = false;
213
+ $obj = wincache_ucache_get($this->_cachePrefix.$cellID.'.cache', $success);
214
+ if ($success === false) {
215
+ // Entry no longer exists in WinCache, so clear it from the cache array
216
+ parent::deleteCacheData($cellID);
217
+ throw new PHPExcel_Exception('Cell entry '.$cellID.' no longer exists in Wincache');
218
+ }
219
+ if (!wincache_ucache_add($newCachePrefix.$cellID.'.cache', $obj, $this->_cacheTime)) {
220
+ $this->__destruct();
221
+ throw new PHPExcel_Exception('Failed to store cell '.$cellID.' in Wincache');
222
+ }
223
+ }
224
+ }
225
+ $this->_cachePrefix = $newCachePrefix;
226
+ } // function copyCellCollection()
227
+
228
+
229
+ /**
230
+ * Clear the cell collection and disconnect from our parent
231
+ *
232
+ * @return void
233
+ */
234
+ public function unsetWorksheetCells() {
235
+ if(!is_null($this->_currentObject)) {
236
+ $this->_currentObject->detach();
237
+ $this->_currentObject = $this->_currentObjectID = null;
238
+ }
239
+
240
+ // Flush the WinCache cache
241
+ $this->__destruct();
242
+
243
+ $this->_cellCache = array();
244
+
245
+ // detach ourself from the worksheet, so that it can then delete this object successfully
246
+ $this->_parent = null;
247
+ } // function unsetWorksheetCells()
248
+
249
+
250
+ /**
251
+ * Initialise this new cell collection
252
+ *
253
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
254
+ * @param array of mixed $arguments Additional initialisation arguments
255
+ */
256
+ public function __construct(PHPExcel_Worksheet $parent, $arguments) {
257
+ $cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600;
258
+
259
+ if (is_null($this->_cachePrefix)) {
260
+ $baseUnique = $this->_getUniqueID();
261
+ $this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
262
+ $this->_cacheTime = $cacheTime;
263
+
264
+ parent::__construct($parent);
265
+ }
266
+ } // function __construct()
267
+
268
+
269
+ /**
270
+ * Destroy this cell collection
271
+ */
272
+ public function __destruct() {
273
+ $cacheList = $this->getCellList();
274
+ foreach($cacheList as $cellID) {
275
+ wincache_ucache_delete($this->_cachePrefix.$cellID.'.cache');
276
+ }
277
+ } // function __destruct()
278
+
279
+
280
+ /**
281
+ * Identify whether the caching method is currently available
282
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
283
+ *
284
+ * @return boolean
285
+ */
286
+ public static function cacheMethodIsAvailable() {
287
+ if (!function_exists('wincache_ucache_add')) {
288
+ return false;
289
+ }
290
+
291
+ return true;
292
+ }
293
+
294
+ }
{libraries → classes}/PHPExcel/CachedObjectStorageFactory.php RENAMED
File without changes
{libraries → classes}/PHPExcel/CalcEngine/CyclicReferenceStack.php RENAMED
File without changes
{libraries → classes}/PHPExcel/CalcEngine/Logger.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/Database.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/DateTime.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/Engineering.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/Exception.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/ExceptionHandler.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/Financial.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/FormulaParser.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/FormulaToken.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/Function.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/Functions.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/Logical.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/LookupRef.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/MathTrig.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/Statistical.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/TextData.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/Token/Stack.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Calculation/functionlist.txt RENAMED
File without changes
{libraries → classes}/PHPExcel/Cell.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Cell/AdvancedValueBinder.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Cell/DataType.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Cell/DataValidation.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Cell/DefaultValueBinder.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Cell/Hyperlink.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Cell/IValueBinder.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Comment.php RENAMED
File without changes
{libraries → classes}/PHPExcel/DocumentProperties.php RENAMED
File without changes
{libraries → classes}/PHPExcel/DocumentSecurity.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Exception.php RENAMED
File without changes
{libraries → classes}/PHPExcel/HashTable.php RENAMED
File without changes
{libraries → classes}/PHPExcel/IComparable.php RENAMED
File without changes
{libraries → classes}/PHPExcel/IOFactory.php RENAMED
File without changes
{libraries → classes}/PHPExcel/NamedRange.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/Abstract.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/CSV.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/DefaultReadFilter.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/Excel2003XML.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/Excel2007.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/Excel2007/Chart.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/Excel2007/Theme.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/Excel5.php RENAMED
@@ -1,7088 +1,7088 @@
1
- <?php
2
- /**
3
- * PHPExcel
4
- *
5
- * Copyright (c) 2006 - 2014 PHPExcel
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
- *
21
- * @category PHPExcel
22
- * @package PHPExcel_Reader_Excel5
23
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
- * @version ##VERSION##, ##DATE##
26
- */
27
-
28
- // Original file header of ParseXL (used as the base for this class):
29
- // --------------------------------------------------------------------------------
30
- // Adapted from Excel_Spreadsheet_Reader developed by users bizon153,
31
- // trex005, and mmp11 (SourceForge.net)
32
- // http://sourceforge.net/projects/phpexcelreader/
33
- // Primary changes made by canyoncasa (dvc) for ParseXL 1.00 ...
34
- // Modelled moreso after Perl Excel Parse/Write modules
35
- // Added Parse_Excel_Spreadsheet object
36
- // Reads a whole worksheet or tab as row,column array or as
37
- // associated hash of indexed rows and named column fields
38
- // Added variables for worksheet (tab) indexes and names
39
- // Added an object call for loading individual woorksheets
40
- // Changed default indexing defaults to 0 based arrays
41
- // Fixed date/time and percent formats
42
- // Includes patches found at SourceForge...
43
- // unicode patch by nobody
44
- // unpack("d") machine depedency patch by matchy
45
- // boundsheet utf16 patch by bjaenichen
46
- // Renamed functions for shorter names
47
- // General code cleanup and rigor, including <80 column width
48
- // Included a testcase Excel file and PHP example calls
49
- // Code works for PHP 5.x
50
-
51
- // Primary changes made by canyoncasa (dvc) for ParseXL 1.10 ...
52
- // http://sourceforge.net/tracker/index.php?func=detail&aid=1466964&group_id=99160&atid=623334
53
- // Decoding of formula conditions, results, and tokens.
54
- // Support for user-defined named cells added as an array "namedcells"
55
- // Patch code for user-defined named cells supports single cells only.
56
- // NOTE: this patch only works for BIFF8 as BIFF5-7 use a different
57
- // external sheet reference structure
58
-
59
-
60
- /** PHPExcel root directory */
61
- if (!defined('PHPEXCEL_ROOT')) {
62
- /**
63
- * @ignore
64
- */
65
- define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
66
- require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
67
- }
68
-
69
- /**
70
- * PHPExcel_Reader_Excel5
71
- *
72
- * This class uses {@link http://sourceforge.net/projects/phpexcelreader/parseXL}
73
- *
74
- * @category PHPExcel
75
- * @package PHPExcel_Reader_Excel5
76
- * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
77
- */
78
- class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
79
- {
80
- // ParseXL definitions
81
- const XLS_BIFF8 = 0x0600;
82
- const XLS_BIFF7 = 0x0500;
83
- const XLS_WorkbookGlobals = 0x0005;
84
- const XLS_Worksheet = 0x0010;
85
-
86
- // record identifiers
87
- const XLS_Type_FORMULA = 0x0006;
88
- const XLS_Type_EOF = 0x000a;
89
- const XLS_Type_PROTECT = 0x0012;
90
- const XLS_Type_OBJECTPROTECT = 0x0063;
91
- const XLS_Type_SCENPROTECT = 0x00dd;
92
- const XLS_Type_PASSWORD = 0x0013;
93
- const XLS_Type_HEADER = 0x0014;
94
- const XLS_Type_FOOTER = 0x0015;
95
- const XLS_Type_EXTERNSHEET = 0x0017;
96
- const XLS_Type_DEFINEDNAME = 0x0018;
97
- const XLS_Type_VERTICALPAGEBREAKS = 0x001a;
98
- const XLS_Type_HORIZONTALPAGEBREAKS = 0x001b;
99
- const XLS_Type_NOTE = 0x001c;
100
- const XLS_Type_SELECTION = 0x001d;
101
- const XLS_Type_DATEMODE = 0x0022;
102
- const XLS_Type_EXTERNNAME = 0x0023;
103
- const XLS_Type_LEFTMARGIN = 0x0026;
104
- const XLS_Type_RIGHTMARGIN = 0x0027;
105
- const XLS_Type_TOPMARGIN = 0x0028;
106
- const XLS_Type_BOTTOMMARGIN = 0x0029;
107
- const XLS_Type_PRINTGRIDLINES = 0x002b;
108
- const XLS_Type_FILEPASS = 0x002f;
109
- const XLS_Type_FONT = 0x0031;
110
- const XLS_Type_CONTINUE = 0x003c;
111
- const XLS_Type_PANE = 0x0041;
112
- const XLS_Type_CODEPAGE = 0x0042;
113
- const XLS_Type_DEFCOLWIDTH = 0x0055;
114
- const XLS_Type_OBJ = 0x005d;
115
- const XLS_Type_COLINFO = 0x007d;
116
- const XLS_Type_IMDATA = 0x007f;
117
- const XLS_Type_SHEETPR = 0x0081;
118
- const XLS_Type_HCENTER = 0x0083;
119
- const XLS_Type_VCENTER = 0x0084;
120
- const XLS_Type_SHEET = 0x0085;
121
- const XLS_Type_PALETTE = 0x0092;
122
- const XLS_Type_SCL = 0x00a0;
123
- const XLS_Type_PAGESETUP = 0x00a1;
124
- const XLS_Type_MULRK = 0x00bd;
125
- const XLS_Type_MULBLANK = 0x00be;
126
- const XLS_Type_DBCELL = 0x00d7;
127
- const XLS_Type_XF = 0x00e0;
128
- const XLS_Type_MERGEDCELLS = 0x00e5;
129
- const XLS_Type_MSODRAWINGGROUP = 0x00eb;
130
- const XLS_Type_MSODRAWING = 0x00ec;
131
- const XLS_Type_SST = 0x00fc;
132
- const XLS_Type_LABELSST = 0x00fd;
133
- const XLS_Type_EXTSST = 0x00ff;
134
- const XLS_Type_EXTERNALBOOK = 0x01ae;
135
- const XLS_Type_DATAVALIDATIONS = 0x01b2;
136
- const XLS_Type_TXO = 0x01b6;
137
- const XLS_Type_HYPERLINK = 0x01b8;
138
- const XLS_Type_DATAVALIDATION = 0x01be;
139
- const XLS_Type_DIMENSION = 0x0200;
140
- const XLS_Type_BLANK = 0x0201;
141
- const XLS_Type_NUMBER = 0x0203;
142
- const XLS_Type_LABEL = 0x0204;
143
- const XLS_Type_BOOLERR = 0x0205;
144
- const XLS_Type_STRING = 0x0207;
145
- const XLS_Type_ROW = 0x0208;
146
- const XLS_Type_INDEX = 0x020b;
147
- const XLS_Type_ARRAY = 0x0221;
148
- const XLS_Type_DEFAULTROWHEIGHT = 0x0225;
149
- const XLS_Type_WINDOW2 = 0x023e;
150
- const XLS_Type_RK = 0x027e;
151
- const XLS_Type_STYLE = 0x0293;
152
- const XLS_Type_FORMAT = 0x041e;
153
- const XLS_Type_SHAREDFMLA = 0x04bc;
154
- const XLS_Type_BOF = 0x0809;
155
- const XLS_Type_SHEETPROTECTION = 0x0867;
156
- const XLS_Type_RANGEPROTECTION = 0x0868;
157
- const XLS_Type_SHEETLAYOUT = 0x0862;
158
- const XLS_Type_XFEXT = 0x087d;
159
- const XLS_Type_PAGELAYOUTVIEW = 0x088b;
160
- const XLS_Type_UNKNOWN = 0xffff;
161
-
162
- // Encryption type
163
- const MS_BIFF_CRYPTO_NONE = 0;
164
- const MS_BIFF_CRYPTO_XOR = 1;
165
- const MS_BIFF_CRYPTO_RC4 = 2;
166
-
167
- // Size of stream blocks when using RC4 encryption
168
- const REKEY_BLOCK = 0x400;
169
-
170
- /**
171
- * Summary Information stream data.
172
- *
173
- * @var string
174
- */
175
- private $_summaryInformation;
176
-
177
- /**
178
- * Extended Summary Information stream data.
179
- *
180
- * @var string
181
- */
182
- private $_documentSummaryInformation;
183
-
184
- /**
185
- * User-Defined Properties stream data.
186
- *
187
- * @var string
188
- */
189
- private $_userDefinedProperties;
190
-
191
- /**
192
- * Workbook stream data. (Includes workbook globals substream as well as sheet substreams)
193
- *
194
- * @var string
195
- */
196
- private $_data;
197
-
198
- /**
199
- * Size in bytes of $this->_data
200
- *
201
- * @var int
202
- */
203
- private $_dataSize;
204
-
205
- /**
206
- * Current position in stream
207
- *
208
- * @var integer
209
- */
210
- private $_pos;
211
-
212
- /**
213
- * Workbook to be returned by the reader.
214
- *
215
- * @var PHPExcel
216
- */
217
- private $_phpExcel;
218
-
219
- /**
220
- * Worksheet that is currently being built by the reader.
221
- *
222
- * @var PHPExcel_Worksheet
223
- */
224
- private $_phpSheet;
225
-
226
- /**
227
- * BIFF version
228
- *
229
- * @var int
230
- */
231
- private $_version;
232
-
233
- /**
234
- * Codepage set in the Excel file being read. Only important for BIFF5 (Excel 5.0 - Excel 95)
235
- * For BIFF8 (Excel 97 - Excel 2003) this will always have the value 'UTF-16LE'
236
- *
237
- * @var string
238
- */
239
- private $_codepage;
240
-
241
- /**
242
- * Shared formats
243
- *
244
- * @var array
245
- */
246
- private $_formats;
247
-
248
- /**
249
- * Shared fonts
250
- *
251
- * @var array
252
- */
253
- private $_objFonts;
254
-
255
- /**
256
- * Color palette
257
- *
258
- * @var array
259
- */
260
- private $_palette;
261
-
262
- /**
263
- * Worksheets
264
- *
265
- * @var array
266
- */
267
- private $_sheets;
268
-
269
- /**
270
- * External books
271
- *
272
- * @var array
273
- */
274
- private $_externalBooks;
275
-
276
- /**
277
- * REF structures. Only applies to BIFF8.
278
- *
279
- * @var array
280
- */
281
- private $_ref;
282
-
283
- /**
284
- * External names
285
- *
286
- * @var array
287
- */
288
- private $_externalNames;
289
-
290
- /**
291
- * Defined names
292
- *
293
- * @var array
294
- */
295
- private $_definedname;
296
-
297
- /**
298
- * Shared strings. Only applies to BIFF8.
299
- *
300
- * @var array
301
- */
302
- private $_sst;
303
-
304
- /**
305
- * Panes are frozen? (in sheet currently being read). See WINDOW2 record.
306
- *
307
- * @var boolean
308
- */
309
- private $_frozen;
310
-
311
- /**
312
- * Fit printout to number of pages? (in sheet currently being read). See SHEETPR record.
313
- *
314
- * @var boolean
315
- */
316
- private $_isFitToPages;
317
-
318
- /**
319
- * Objects. One OBJ record contributes with one entry.
320
- *
321
- * @var array
322
- */
323
- private $_objs;
324
-
325
- /**
326
- * Text Objects. One TXO record corresponds with one entry.
327
- *
328
- * @var array
329
- */
330
- private $_textObjects;
331
-
332
- /**
333
- * Cell Annotations (BIFF8)
334
- *
335
- * @var array
336
- */
337
- private $_cellNotes;
338
-
339
- /**
340
- * The combined MSODRAWINGGROUP data
341
- *
342
- * @var string
343
- */
344
- private $_drawingGroupData;
345
-
346
- /**
347
- * The combined MSODRAWING data (per sheet)
348
- *
349
- * @var string
350
- */
351
- private $_drawingData;
352
-
353
- /**
354
- * Keep track of XF index
355
- *
356
- * @var int
357
- */
358
- private $_xfIndex;
359
-
360
- /**
361
- * Mapping of XF index (that is a cell XF) to final index in cellXf collection
362
- *
363
- * @var array
364
- */
365
- private $_mapCellXfIndex;
366
-
367
- /**
368
- * Mapping of XF index (that is a style XF) to final index in cellStyleXf collection
369
- *
370
- * @var array
371
- */
372
- private $_mapCellStyleXfIndex;
373
-
374
- /**
375
- * The shared formulas in a sheet. One SHAREDFMLA record contributes with one value.
376
- *
377
- * @var array
378
- */
379
- private $_sharedFormulas;
380
-
381
- /**
382
- * The shared formula parts in a sheet. One FORMULA record contributes with one value if it
383
- * refers to a shared formula.
384
- *
385
- * @var array
386
- */
387
- private $_sharedFormulaParts;
388
-
389
- /**
390
- * The type of encryption in use
391
- *
392
- * @var int
393
- */
394
- private $_encryption = 0;
395
-
396
- /**
397
- * The position in the stream after which contents are encrypted
398
- *
399
- * @var int
400
- */
401
- private $_encryptionStartPos = false;
402
-
403
- /**
404
- * The current RC4 decryption object
405
- *
406
- * @var PHPExcel_Reader_Excel5_RC4
407
- */
408
- private $_rc4Key = null;
409
-
410
- /**
411
- * The position in the stream that the RC4 decryption object was left at
412
- *
413
- * @var int
414
- */
415
- private $_rc4Pos = 0;
416
-
417
- /**
418
- * The current MD5 context state
419
- *
420
- * @var string
421
- */
422
- private $_md5Ctxt = null;
423
-
424
- /**
425
- * Create a new PHPExcel_Reader_Excel5 instance
426
- */
427
- public function __construct() {
428
- $this->_readFilter = new PHPExcel_Reader_DefaultReadFilter();
429
- }
430
-
431
-
432
- /**
433
- * Can the current PHPExcel_Reader_IReader read the file?
434
- *
435
- * @param string $pFilename
436
- * @return boolean
437
- * @throws PHPExcel_Reader_Exception
438
- */
439
- public function canRead($pFilename)
440
- {
441
- // Check if file exists
442
- if (!file_exists($pFilename)) {
443
- throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
444
- }
445
-
446
- try {
447
- // Use ParseXL for the hard work.
448
- $ole = new PHPExcel_Shared_OLERead();
449
-
450
- // get excel data
451
- $res = $ole->read($pFilename);
452
- return true;
453
- } catch (PHPExcel_Exception $e) {
454
- return false;
455
- }
456
- }
457
-
458
-
459
- /**
460
- * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
461
- *
462
- * @param string $pFilename
463
- * @throws PHPExcel_Reader_Exception
464
- */
465
- public function listWorksheetNames($pFilename)
466
- {
467
- // Check if file exists
468
- if (!file_exists($pFilename)) {
469
- throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
470
- }
471
-
472
- $worksheetNames = array();
473
-
474
- // Read the OLE file
475
- $this->_loadOLE($pFilename);
476
-
477
- // total byte size of Excel data (workbook global substream + sheet substreams)
478
- $this->_dataSize = strlen($this->_data);
479
-
480
- $this->_pos = 0;
481
- $this->_sheets = array();
482
-
483
- // Parse Workbook Global Substream
484
- while ($this->_pos < $this->_dataSize) {
485
- $code = self::_GetInt2d($this->_data, $this->_pos);
486
-
487
- switch ($code) {
488
- case self::XLS_Type_BOF: $this->_readBof(); break;
489
- case self::XLS_Type_SHEET: $this->_readSheet(); break;
490
- case self::XLS_Type_EOF: $this->_readDefault(); break 2;
491
- default: $this->_readDefault(); break;
492
- }
493
- }
494
-
495
- foreach ($this->_sheets as $sheet) {
496
- if ($sheet['sheetType'] != 0x00) {
497
- // 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
498
- continue;
499
- }
500
-
501
- $worksheetNames[] = $sheet['name'];
502
- }
503
-
504
- return $worksheetNames;
505
- }
506
-
507
-
508
- /**
509
- * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
510
- *
511
- * @param string $pFilename
512
- * @throws PHPExcel_Reader_Exception
513
- */
514
- public function listWorksheetInfo($pFilename)
515
- {
516
- // Check if file exists
517
- if (!file_exists($pFilename)) {
518
- throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
519
- }
520
-
521
- $worksheetInfo = array();
522
-
523
- // Read the OLE file
524
- $this->_loadOLE($pFilename);
525
-
526
- // total byte size of Excel data (workbook global substream + sheet substreams)
527
- $this->_dataSize = strlen($this->_data);
528
-
529
- // initialize
530
- $this->_pos = 0;
531
- $this->_sheets = array();
532
-
533
- // Parse Workbook Global Substream
534
- while ($this->_pos < $this->_dataSize) {
535
- $code = self::_GetInt2d($this->_data, $this->_pos);
536
-
537
- switch ($code) {
538
- case self::XLS_Type_BOF: $this->_readBof(); break;
539
- case self::XLS_Type_SHEET: $this->_readSheet(); break;
540
- case self::XLS_Type_EOF: $this->_readDefault(); break 2;
541
- default: $this->_readDefault(); break;
542
- }
543
- }
544
-
545
- // Parse the individual sheets
546
- foreach ($this->_sheets as $sheet) {
547
-
548
- if ($sheet['sheetType'] != 0x00) {
549
- // 0x00: Worksheet
550
- // 0x02: Chart
551
- // 0x06: Visual Basic module
552
- continue;
553
- }
554
-
555
- $tmpInfo = array();
556
- $tmpInfo['worksheetName'] = $sheet['name'];
557
- $tmpInfo['lastColumnLetter'] = 'A';
558
- $tmpInfo['lastColumnIndex'] = 0;
559
- $tmpInfo['totalRows'] = 0;
560
- $tmpInfo['totalColumns'] = 0;
561
-
562
- $this->_pos = $sheet['offset'];
563
-
564
- while ($this->_pos <= $this->_dataSize - 4) {
565
- $code = self::_GetInt2d($this->_data, $this->_pos);
566
-
567
- switch ($code) {
568
- case self::XLS_Type_RK:
569
- case self::XLS_Type_LABELSST:
570
- case self::XLS_Type_NUMBER:
571
- case self::XLS_Type_FORMULA:
572
- case self::XLS_Type_BOOLERR:
573
- case self::XLS_Type_LABEL:
574
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
575
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
576
-
577
- // move stream pointer to next record
578
- $this->_pos += 4 + $length;
579
-
580
- $rowIndex = self::_GetInt2d($recordData, 0) + 1;
581
- $columnIndex = self::_GetInt2d($recordData, 2);
582
-
583
- $tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
584
- $tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
585
- break;
586
- case self::XLS_Type_BOF: $this->_readBof(); break;
587
- case self::XLS_Type_EOF: $this->_readDefault(); break 2;
588
- default: $this->_readDefault(); break;
589
- }
590
- }
591
-
592
- $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
593
- $tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
594
-
595
- $worksheetInfo[] = $tmpInfo;
596
- }
597
-
598
- return $worksheetInfo;
599
- }
600
-
601
-
602
- /**
603
- * Loads PHPExcel from file
604
- *
605
- * @param string $pFilename
606
- * @return PHPExcel
607
- * @throws PHPExcel_Reader_Exception
608
- */
609
- public function load($pFilename)
610
- {
611
- // Read the OLE file
612
- $this->_loadOLE($pFilename);
613
-
614
- // Initialisations
615
- $this->_phpExcel = new PHPExcel;
616
- $this->_phpExcel->removeSheetByIndex(0); // remove 1st sheet
617
- if (!$this->_readDataOnly) {
618
- $this->_phpExcel->removeCellStyleXfByIndex(0); // remove the default style
619
- $this->_phpExcel->removeCellXfByIndex(0); // remove the default style
620
- }
621
-
622
- // Read the summary information stream (containing meta data)
623
- $this->_readSummaryInformation();
624
-
625
- // Read the Additional document summary information stream (containing application-specific meta data)
626
- $this->_readDocumentSummaryInformation();
627
-
628
- // total byte size of Excel data (workbook global substream + sheet substreams)
629
- $this->_dataSize = strlen($this->_data);
630
-
631
- // initialize
632
- $this->_pos = 0;
633
- $this->_codepage = 'CP1252';
634
- $this->_formats = array();
635
- $this->_objFonts = array();
636
- $this->_palette = array();
637
- $this->_sheets = array();
638
- $this->_externalBooks = array();
639
- $this->_ref = array();
640
- $this->_definedname = array();
641
- $this->_sst = array();
642
- $this->_drawingGroupData = '';
643
- $this->_xfIndex = '';
644
- $this->_mapCellXfIndex = array();
645
- $this->_mapCellStyleXfIndex = array();
646
-
647
- // Parse Workbook Global Substream
648
- while ($this->_pos < $this->_dataSize) {
649
- $code = self::_GetInt2d($this->_data, $this->_pos);
650
-
651
- switch ($code) {
652
- case self::XLS_Type_BOF: $this->_readBof(); break;
653
- case self::XLS_Type_FILEPASS: $this->_readFilepass(); break;
654
- case self::XLS_Type_CODEPAGE: $this->_readCodepage(); break;
655
- case self::XLS_Type_DATEMODE: $this->_readDateMode(); break;
656
- case self::XLS_Type_FONT: $this->_readFont(); break;
657
- case self::XLS_Type_FORMAT: $this->_readFormat(); break;
658
- case self::XLS_Type_XF: $this->_readXf(); break;
659
- case self::XLS_Type_XFEXT: $this->_readXfExt(); break;
660
- case self::XLS_Type_STYLE: $this->_readStyle(); break;
661
- case self::XLS_Type_PALETTE: $this->_readPalette(); break;
662
- case self::XLS_Type_SHEET: $this->_readSheet(); break;
663
- case self::XLS_Type_EXTERNALBOOK: $this->_readExternalBook(); break;
664
- case self::XLS_Type_EXTERNNAME: $this->_readExternName(); break;
665
- case self::XLS_Type_EXTERNSHEET: $this->_readExternSheet(); break;
666
- case self::XLS_Type_DEFINEDNAME: $this->_readDefinedName(); break;
667
- case self::XLS_Type_MSODRAWINGGROUP: $this->_readMsoDrawingGroup(); break;
668
- case self::XLS_Type_SST: $this->_readSst(); break;
669
- case self::XLS_Type_EOF: $this->_readDefault(); break 2;
670
- default: $this->_readDefault(); break;
671
- }
672
- }
673
-
674
- // Resolve indexed colors for font, fill, and border colors
675
- // Cannot be resolved already in XF record, because PALETTE record comes afterwards
676
- if (!$this->_readDataOnly) {
677
- foreach ($this->_objFonts as $objFont) {
678
- if (isset($objFont->colorIndex)) {
679
- $color = self::_readColor($objFont->colorIndex,$this->_palette,$this->_version);
680
- $objFont->getColor()->setRGB($color['rgb']);
681
- }
682
- }
683
-
684
- foreach ($this->_phpExcel->getCellXfCollection() as $objStyle) {
685
- // fill start and end color
686
- $fill = $objStyle->getFill();
687
-
688
- if (isset($fill->startcolorIndex)) {
689
- $startColor = self::_readColor($fill->startcolorIndex,$this->_palette,$this->_version);
690
- $fill->getStartColor()->setRGB($startColor['rgb']);
691
- }
692
-
693
- if (isset($fill->endcolorIndex)) {
694
- $endColor = self::_readColor($fill->endcolorIndex,$this->_palette,$this->_version);
695
- $fill->getEndColor()->setRGB($endColor['rgb']);
696
- }
697
-
698
- // border colors
699
- $top = $objStyle->getBorders()->getTop();
700
- $right = $objStyle->getBorders()->getRight();
701
- $bottom = $objStyle->getBorders()->getBottom();
702
- $left = $objStyle->getBorders()->getLeft();
703
- $diagonal = $objStyle->getBorders()->getDiagonal();
704
-
705
- if (isset($top->colorIndex)) {
706
- $borderTopColor = self::_readColor($top->colorIndex,$this->_palette,$this->_version);
707
- $top->getColor()->setRGB($borderTopColor['rgb']);
708
- }
709
-
710
- if (isset($right->colorIndex)) {
711
- $borderRightColor = self::_readColor($right->colorIndex,$this->_palette,$this->_version);
712
- $right->getColor()->setRGB($borderRightColor['rgb']);
713
- }
714
-
715
- if (isset($bottom->colorIndex)) {
716
- $borderBottomColor = self::_readColor($bottom->colorIndex,$this->_palette,$this->_version);
717
- $bottom->getColor()->setRGB($borderBottomColor['rgb']);
718
- }
719
-
720
- if (isset($left->colorIndex)) {
721
- $borderLeftColor = self::_readColor($left->colorIndex,$this->_palette,$this->_version);
722
- $left->getColor()->setRGB($borderLeftColor['rgb']);
723
- }
724
-
725
- if (isset($diagonal->colorIndex)) {
726
- $borderDiagonalColor = self::_readColor($diagonal->colorIndex,$this->_palette,$this->_version);
727
- $diagonal->getColor()->setRGB($borderDiagonalColor['rgb']);
728
- }
729
- }
730
- }
731
-
732
- // treat MSODRAWINGGROUP records, workbook-level Escher
733
- if (!$this->_readDataOnly && $this->_drawingGroupData) {
734
- $escherWorkbook = new PHPExcel_Shared_Escher();
735
- $reader = new PHPExcel_Reader_Excel5_Escher($escherWorkbook);
736
- $escherWorkbook = $reader->load($this->_drawingGroupData);
737
-
738
- // debug Escher stream
739
- //$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
740
- //$debug->load($this->_drawingGroupData);
741
- }
742
-
743
- // Parse the individual sheets
744
- foreach ($this->_sheets as $sheet) {
745
-
746
- if ($sheet['sheetType'] != 0x00) {
747
- // 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
748
- continue;
749
- }
750
-
751
- // check if sheet should be skipped
752
- if (isset($this->_loadSheetsOnly) && !in_array($sheet['name'], $this->_loadSheetsOnly)) {
753
- continue;
754
- }
755
-
756
- // add sheet to PHPExcel object
757
- $this->_phpSheet = $this->_phpExcel->createSheet();
758
- // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
759
- // cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
760
- // name in line with the formula, not the reverse
761
- $this->_phpSheet->setTitle($sheet['name'],false);
762
- $this->_phpSheet->setSheetState($sheet['sheetState']);
763
-
764
- $this->_pos = $sheet['offset'];
765
-
766
- // Initialize isFitToPages. May change after reading SHEETPR record.
767
- $this->_isFitToPages = false;
768
-
769
- // Initialize drawingData
770
- $this->_drawingData = '';
771
-
772
- // Initialize objs
773
- $this->_objs = array();
774
-
775
- // Initialize shared formula parts
776
- $this->_sharedFormulaParts = array();
777
-
778
- // Initialize shared formulas
779
- $this->_sharedFormulas = array();
780
-
781
- // Initialize text objs
782
- $this->_textObjects = array();
783
-
784
- // Initialize cell annotations
785
- $this->_cellNotes = array();
786
- $this->textObjRef = -1;
787
-
788
- while ($this->_pos <= $this->_dataSize - 4) {
789
- $code = self::_GetInt2d($this->_data, $this->_pos);
790
-
791
- switch ($code) {
792
- case self::XLS_Type_BOF: $this->_readBof(); break;
793
- case self::XLS_Type_PRINTGRIDLINES: $this->_readPrintGridlines(); break;
794
- case self::XLS_Type_DEFAULTROWHEIGHT: $this->_readDefaultRowHeight(); break;
795
- case self::XLS_Type_SHEETPR: $this->_readSheetPr(); break;
796
- case self::XLS_Type_HORIZONTALPAGEBREAKS: $this->_readHorizontalPageBreaks(); break;
797
- case self::XLS_Type_VERTICALPAGEBREAKS: $this->_readVerticalPageBreaks(); break;
798
- case self::XLS_Type_HEADER: $this->_readHeader(); break;
799
- case self::XLS_Type_FOOTER: $this->_readFooter(); break;
800
- case self::XLS_Type_HCENTER: $this->_readHcenter(); break;
801
- case self::XLS_Type_VCENTER: $this->_readVcenter(); break;
802
- case self::XLS_Type_LEFTMARGIN: $this->_readLeftMargin(); break;
803
- case self::XLS_Type_RIGHTMARGIN: $this->_readRightMargin(); break;
804
- case self::XLS_Type_TOPMARGIN: $this->_readTopMargin(); break;
805
- case self::XLS_Type_BOTTOMMARGIN: $this->_readBottomMargin(); break;
806
- case self::XLS_Type_PAGESETUP: $this->_readPageSetup(); break;
807
- case self::XLS_Type_PROTECT: $this->_readProtect(); break;
808
- case self::XLS_Type_SCENPROTECT: $this->_readScenProtect(); break;
809
- case self::XLS_Type_OBJECTPROTECT: $this->_readObjectProtect(); break;
810
- case self::XLS_Type_PASSWORD: $this->_readPassword(); break;
811
- case self::XLS_Type_DEFCOLWIDTH: $this->_readDefColWidth(); break;
812
- case self::XLS_Type_COLINFO: $this->_readColInfo(); break;
813
- case self::XLS_Type_DIMENSION: $this->_readDefault(); break;
814
- case self::XLS_Type_ROW: $this->_readRow(); break;
815
- case self::XLS_Type_DBCELL: $this->_readDefault(); break;
816
- case self::XLS_Type_RK: $this->_readRk(); break;
817
- case self::XLS_Type_LABELSST: $this->_readLabelSst(); break;
818
- case self::XLS_Type_MULRK: $this->_readMulRk(); break;
819
- case self::XLS_Type_NUMBER: $this->_readNumber(); break;
820
- case self::XLS_Type_FORMULA: $this->_readFormula(); break;
821
- case self::XLS_Type_SHAREDFMLA: $this->_readSharedFmla(); break;
822
- case self::XLS_Type_BOOLERR: $this->_readBoolErr(); break;
823
- case self::XLS_Type_MULBLANK: $this->_readMulBlank(); break;
824
- case self::XLS_Type_LABEL: $this->_readLabel(); break;
825
- case self::XLS_Type_BLANK: $this->_readBlank(); break;
826
- case self::XLS_Type_MSODRAWING: $this->_readMsoDrawing(); break;
827
- case self::XLS_Type_OBJ: $this->_readObj(); break;
828
- case self::XLS_Type_WINDOW2: $this->_readWindow2(); break;
829
- case self::XLS_Type_PAGELAYOUTVIEW: $this->_readPageLayoutView(); break;
830
- case self::XLS_Type_SCL: $this->_readScl(); break;
831
- case self::XLS_Type_PANE: $this->_readPane(); break;
832
- case self::XLS_Type_SELECTION: $this->_readSelection(); break;
833
- case self::XLS_Type_MERGEDCELLS: $this->_readMergedCells(); break;
834
- case self::XLS_Type_HYPERLINK: $this->_readHyperLink(); break;
835
- case self::XLS_Type_DATAVALIDATIONS: $this->_readDataValidations(); break;
836
- case self::XLS_Type_DATAVALIDATION: $this->_readDataValidation(); break;
837
- case self::XLS_Type_SHEETLAYOUT: $this->_readSheetLayout(); break;
838
- case self::XLS_Type_SHEETPROTECTION: $this->_readSheetProtection(); break;
839
- case self::XLS_Type_RANGEPROTECTION: $this->_readRangeProtection(); break;
840
- case self::XLS_Type_NOTE: $this->_readNote(); break;
841
- //case self::XLS_Type_IMDATA: $this->_readImData(); break;
842
- case self::XLS_Type_TXO: $this->_readTextObject(); break;
843
- case self::XLS_Type_CONTINUE: $this->_readContinue(); break;
844
- case self::XLS_Type_EOF: $this->_readDefault(); break 2;
845
- default: $this->_readDefault(); break;
846
- }
847
-
848
- }
849
-
850
- // treat MSODRAWING records, sheet-level Escher
851
- if (!$this->_readDataOnly && $this->_drawingData) {
852
- $escherWorksheet = new PHPExcel_Shared_Escher();
853
- $reader = new PHPExcel_Reader_Excel5_Escher($escherWorksheet);
854
- $escherWorksheet = $reader->load($this->_drawingData);
855
-
856
- // debug Escher stream
857
- //$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
858
- //$debug->load($this->_drawingData);
859
-
860
- // get all spContainers in one long array, so they can be mapped to OBJ records
861
- $allSpContainers = $escherWorksheet->getDgContainer()->getSpgrContainer()->getAllSpContainers();
862
- }
863
-
864
- // treat OBJ records
865
- foreach ($this->_objs as $n => $obj) {
866
- // echo '<hr /><b>Object</b> reference is ',$n,'<br />';
867
- // var_dump($obj);
868
- // echo '<br />';
869
-
870
- // the first shape container never has a corresponding OBJ record, hence $n + 1
871
- if (isset($allSpContainers[$n + 1]) && is_object($allSpContainers[$n + 1])) {
872
- $spContainer = $allSpContainers[$n + 1];
873
-
874
- // we skip all spContainers that are a part of a group shape since we cannot yet handle those
875
- if ($spContainer->getNestingLevel() > 1) {
876
- continue;
877
- }
878
-
879
- // calculate the width and height of the shape
880
- list($startColumn, $startRow) = PHPExcel_Cell::coordinateFromString($spContainer->getStartCoordinates());
881
- list($endColumn, $endRow) = PHPExcel_Cell::coordinateFromString($spContainer->getEndCoordinates());
882
-
883
- $startOffsetX = $spContainer->getStartOffsetX();
884
- $startOffsetY = $spContainer->getStartOffsetY();
885
- $endOffsetX = $spContainer->getEndOffsetX();
886
- $endOffsetY = $spContainer->getEndOffsetY();
887
-
888
- $width = PHPExcel_Shared_Excel5::getDistanceX($this->_phpSheet, $startColumn, $startOffsetX, $endColumn, $endOffsetX);
889
- $height = PHPExcel_Shared_Excel5::getDistanceY($this->_phpSheet, $startRow, $startOffsetY, $endRow, $endOffsetY);
890
-
891
- // calculate offsetX and offsetY of the shape
892
- $offsetX = $startOffsetX * PHPExcel_Shared_Excel5::sizeCol($this->_phpSheet, $startColumn) / 1024;
893
- $offsetY = $startOffsetY * PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet, $startRow) / 256;
894
-
895
- switch ($obj['otObjType']) {
896
- case 0x19:
897
- // Note
898
- // echo 'Cell Annotation Object<br />';
899
- // echo 'Object ID is ',$obj['idObjID'],'<br />';
900
- //
901
- if (isset($this->_cellNotes[$obj['idObjID']])) {
902
- $cellNote = $this->_cellNotes[$obj['idObjID']];
903
-
904
- if (isset($this->_textObjects[$obj['idObjID']])) {
905
- $textObject = $this->_textObjects[$obj['idObjID']];
906
- $this->_cellNotes[$obj['idObjID']]['objTextData'] = $textObject;
907
- }
908
- }
909
- break;
910
-
911
- case 0x08:
912
- // echo 'Picture Object<br />';
913
- // picture
914
-
915
- // get index to BSE entry (1-based)
916
- $BSEindex = $spContainer->getOPT(0x0104);
917
- $BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection();
918
- $BSE = $BSECollection[$BSEindex - 1];
919
- $blipType = $BSE->getBlipType();
920
-
921
- // need check because some blip types are not supported by Escher reader such as EMF
922
- if ($blip = $BSE->getBlip()) {
923
- $ih = imagecreatefromstring($blip->getData());
924
- $drawing = new PHPExcel_Worksheet_MemoryDrawing();
925
- $drawing->setImageResource($ih);
926
-
927
- // width, height, offsetX, offsetY
928
- $drawing->setResizeProportional(false);
929
- $drawing->setWidth($width);
930
- $drawing->setHeight($height);
931
- $drawing->setOffsetX($offsetX);
932
- $drawing->setOffsetY($offsetY);
933
-
934
- switch ($blipType) {
935
- case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG:
936
- $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_JPEG);
937
- $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG);
938
- break;
939
-
940
- case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG:
941
- $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG);
942
- $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG);
943
- break;
944
- }
945
-
946
- $drawing->setWorksheet($this->_phpSheet);
947
- $drawing->setCoordinates($spContainer->getStartCoordinates());
948
- }
949
-
950
- break;
951
-
952
- default:
953
- // other object type
954
- break;
955
-
956
- }
957
- }
958
- }
959
-
960
- // treat SHAREDFMLA records
961
- if ($this->_version == self::XLS_BIFF8) {
962
- foreach ($this->_sharedFormulaParts as $cell => $baseCell) {
963
- list($column, $row) = PHPExcel_Cell::coordinateFromString($cell);
964
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle()) ) {
965
- $formula = $this->_getFormulaFromStructure($this->_sharedFormulas[$baseCell], $cell);
966
- $this->_phpSheet->getCell($cell)->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
967
- }
968
- }
969
- }
970
-
971
- if (!empty($this->_cellNotes)) {
972
- foreach($this->_cellNotes as $note => $noteDetails) {
973
- if (!isset($noteDetails['objTextData'])) {
974
- if (isset($this->_textObjects[$note])) {
975
- $textObject = $this->_textObjects[$note];
976
- $noteDetails['objTextData'] = $textObject;
977
- } else {
978
- $noteDetails['objTextData']['text'] = '';
979
- }
980
- }
981
- // echo '<b>Cell annotation ',$note,'</b><br />';
982
- // var_dump($noteDetails);
983
- // echo '<br />';
984
- $cellAddress = str_replace('$','',$noteDetails['cellRef']);
985
- $this->_phpSheet->getComment( $cellAddress )
986
- ->setAuthor( $noteDetails['author'] )
987
- ->setText($this->_parseRichText($noteDetails['objTextData']['text']) );
988
- }
989
- }
990
- }
991
-
992
- // add the named ranges (defined names)
993
- foreach ($this->_definedname as $definedName) {
994
- if ($definedName['isBuiltInName']) {
995
- switch ($definedName['name']) {
996
-
997
- case pack('C', 0x06):
998
- // print area
999
- // in general, formula looks like this: Foo!$C$7:$J$66,Bar!$A$1:$IV$2
1000
- $ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
1001
-
1002
- $extractedRanges = array();
1003
- foreach ($ranges as $range) {
1004
- // $range should look like one of these
1005
- // Foo!$C$7:$J$66
1006
- // Bar!$A$1:$IV$2
1007
-
1008
- $explodes = explode('!', $range); // FIXME: what if sheetname contains exclamation mark?
1009
- $sheetName = trim($explodes[0], "'");
1010
-
1011
- if (count($explodes) == 2) {
1012
- if (strpos($explodes[1], ':') === FALSE) {
1013
- $explodes[1] = $explodes[1] . ':' . $explodes[1];
1014
- }
1015
- $extractedRanges[] = str_replace('$', '', $explodes[1]); // C7:J66
1016
- }
1017
- }
1018
- if ($docSheet = $this->_phpExcel->getSheetByName($sheetName)) {
1019
- $docSheet->getPageSetup()->setPrintArea(implode(',', $extractedRanges)); // C7:J66,A1:IV2
1020
- }
1021
- break;
1022
-
1023
- case pack('C', 0x07):
1024
- // print titles (repeating rows)
1025
- // Assuming BIFF8, there are 3 cases
1026
- // 1. repeating rows
1027
- // formula looks like this: Sheet!$A$1:$IV$2
1028
- // rows 1-2 repeat
1029
- // 2. repeating columns
1030
- // formula looks like this: Sheet!$A$1:$B$65536
1031
- // columns A-B repeat
1032
- // 3. both repeating rows and repeating columns
1033
- // formula looks like this: Sheet!$A$1:$B$65536,Sheet!$A$1:$IV$2
1034
-
1035
- $ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
1036
-
1037
- foreach ($ranges as $range) {
1038
- // $range should look like this one of these
1039
- // Sheet!$A$1:$B$65536
1040
- // Sheet!$A$1:$IV$2
1041
-
1042
- $explodes = explode('!', $range);
1043
-
1044
- if (count($explodes) == 2) {
1045
- if ($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) {
1046
-
1047
- $extractedRange = $explodes[1];
1048
- $extractedRange = str_replace('$', '', $extractedRange);
1049
-
1050
- $coordinateStrings = explode(':', $extractedRange);
1051
- if (count($coordinateStrings) == 2) {
1052
- list($firstColumn, $firstRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[0]);
1053
- list($lastColumn, $lastRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[1]);
1054
-
1055
- if ($firstColumn == 'A' and $lastColumn == 'IV') {
1056
- // then we have repeating rows
1057
- $docSheet->getPageSetup()->setRowsToRepeatAtTop(array($firstRow, $lastRow));
1058
- } elseif ($firstRow == 1 and $lastRow == 65536) {
1059
- // then we have repeating columns
1060
- $docSheet->getPageSetup()->setColumnsToRepeatAtLeft(array($firstColumn, $lastColumn));
1061
- }
1062
- }
1063
- }
1064
- }
1065
- }
1066
- break;
1067
-
1068
- }
1069
- } else {
1070
- // Extract range
1071
- $explodes = explode('!', $definedName['formula']);
1072
-
1073
- if (count($explodes) == 2) {
1074
- if (($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) ||
1075
- ($docSheet = $this->_phpExcel->getSheetByName(trim($explodes[0],"'")))) {
1076
- $extractedRange = $explodes[1];
1077
- $extractedRange = str_replace('$', '', $extractedRange);
1078
-
1079
- $localOnly = ($definedName['scope'] == 0) ? false : true;
1080
-
1081
- $scope = ($definedName['scope'] == 0) ?
1082
- null : $this->_phpExcel->getSheetByName($this->_sheets[$definedName['scope'] - 1]['name']);
1083
-
1084
- $this->_phpExcel->addNamedRange( new PHPExcel_NamedRange((string)$definedName['name'], $docSheet, $extractedRange, $localOnly, $scope) );
1085
- }
1086
- } else {
1087
- // Named Value
1088
- // TODO Provide support for named values
1089
- }
1090
- }
1091
- }
1092
- $this->_data = null;
1093
-
1094
- return $this->_phpExcel;
1095
- }
1096
-
1097
- /**
1098
- * Read record data from stream, decrypting as required
1099
- *
1100
- * @param string $data Data stream to read from
1101
- * @param int $pos Position to start reading from
1102
- * @param int $length Record data length
1103
- *
1104
- * @return string Record data
1105
- */
1106
- private function _readRecordData($data, $pos, $len)
1107
- {
1108
- $data = substr($data, $pos, $len);
1109
-
1110
- // File not encrypted, or record before encryption start point
1111
- if ($this->_encryption == self::MS_BIFF_CRYPTO_NONE || $pos < $this->_encryptionStartPos) {
1112
- return $data;
1113
- }
1114
-
1115
- $recordData = '';
1116
- if ($this->_encryption == self::MS_BIFF_CRYPTO_RC4) {
1117
-
1118
- $oldBlock = floor($this->_rc4Pos / self::REKEY_BLOCK);
1119
- $block = floor($pos / self::REKEY_BLOCK);
1120
- $endBlock = floor(($pos + $len) / self::REKEY_BLOCK);
1121
-
1122
- // Spin an RC4 decryptor to the right spot. If we have a decryptor sitting
1123
- // at a point earlier in the current block, re-use it as we can save some time.
1124
- if ($block != $oldBlock || $pos < $this->_rc4Pos || !$this->_rc4Key) {
1125
- $this->_rc4Key = $this->_makeKey($block, $this->_md5Ctxt);
1126
- $step = $pos % self::REKEY_BLOCK;
1127
- } else {
1128
- $step = $pos - $this->_rc4Pos;
1129
- }
1130
- $this->_rc4Key->RC4(str_repeat("\0", $step));
1131
-
1132
- // Decrypt record data (re-keying at the end of every block)
1133
- while ($block != $endBlock) {
1134
- $step = self::REKEY_BLOCK - ($pos % self::REKEY_BLOCK);
1135
- $recordData .= $this->_rc4Key->RC4(substr($data, 0, $step));
1136
- $data = substr($data, $step);
1137
- $pos += $step;
1138
- $len -= $step;
1139
- $block++;
1140
- $this->_rc4Key = $this->_makeKey($block, $this->_md5Ctxt);
1141
- }
1142
- $recordData .= $this->_rc4Key->RC4(substr($data, 0, $len));
1143
-
1144
- // Keep track of the position of this decryptor.
1145
- // We'll try and re-use it later if we can to speed things up
1146
- $this->_rc4Pos = $pos + $len;
1147
-
1148
- } elseif ($this->_encryption == self::MS_BIFF_CRYPTO_XOR) {
1149
- throw new PHPExcel_Reader_Exception('XOr encryption not supported');
1150
- }
1151
- return $recordData;
1152
- }
1153
-
1154
- /**
1155
- * Use OLE reader to extract the relevant data streams from the OLE file
1156
- *
1157
- * @param string $pFilename
1158
- */
1159
- private function _loadOLE($pFilename)
1160
- {
1161
- // OLE reader
1162
- $ole = new PHPExcel_Shared_OLERead();
1163
-
1164
- // get excel data,
1165
- $res = $ole->read($pFilename);
1166
- // Get workbook data: workbook stream + sheet streams
1167
- $this->_data = $ole->getStream($ole->wrkbook);
1168
-
1169
- // Get summary information data
1170
- $this->_summaryInformation = $ole->getStream($ole->summaryInformation);
1171
-
1172
- // Get additional document summary information data
1173
- $this->_documentSummaryInformation = $ole->getStream($ole->documentSummaryInformation);
1174
-
1175
- // Get user-defined property data
1176
- // $this->_userDefinedProperties = $ole->getUserDefinedProperties();
1177
- }
1178
-
1179
-
1180
- /**
1181
- * Read summary information
1182
- */
1183
- private function _readSummaryInformation()
1184
- {
1185
- if (!isset($this->_summaryInformation)) {
1186
- return;
1187
- }
1188
-
1189
- // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
1190
- // offset: 2; size: 2;
1191
- // offset: 4; size: 2; OS version
1192
- // offset: 6; size: 2; OS indicator
1193
- // offset: 8; size: 16
1194
- // offset: 24; size: 4; section count
1195
- $secCount = self::_GetInt4d($this->_summaryInformation, 24);
1196
-
1197
- // offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9
1198
- // offset: 44; size: 4
1199
- $secOffset = self::_GetInt4d($this->_summaryInformation, 44);
1200
-
1201
- // section header
1202
- // offset: $secOffset; size: 4; section length
1203
- $secLength = self::_GetInt4d($this->_summaryInformation, $secOffset);
1204
-
1205
- // offset: $secOffset+4; size: 4; property count
1206
- $countProperties = self::_GetInt4d($this->_summaryInformation, $secOffset+4);
1207
-
1208
- // initialize code page (used to resolve string values)
1209
- $codePage = 'CP1252';
1210
-
1211
- // offset: ($secOffset+8); size: var
1212
- // loop through property decarations and properties
1213
- for ($i = 0; $i < $countProperties; ++$i) {
1214
-
1215
- // offset: ($secOffset+8) + (8 * $i); size: 4; property ID
1216
- $id = self::_GetInt4d($this->_summaryInformation, ($secOffset+8) + (8 * $i));
1217
-
1218
- // Use value of property id as appropriate
1219
- // offset: ($secOffset+12) + (8 * $i); size: 4; offset from beginning of section (48)
1220
- $offset = self::_GetInt4d($this->_summaryInformation, ($secOffset+12) + (8 * $i));
1221
-
1222
- $type = self::_GetInt4d($this->_summaryInformation, $secOffset + $offset);
1223
-
1224
- // initialize property value
1225
- $value = null;
1226
-
1227
- // extract property value based on property type
1228
- switch ($type) {
1229
- case 0x02: // 2 byte signed integer
1230
- $value = self::_GetInt2d($this->_summaryInformation, $secOffset + 4 + $offset);
1231
- break;
1232
-
1233
- case 0x03: // 4 byte signed integer
1234
- $value = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
1235
- break;
1236
-
1237
- case 0x13: // 4 byte unsigned integer
1238
- // not needed yet, fix later if necessary
1239
- break;
1240
-
1241
- case 0x1E: // null-terminated string prepended by dword string length
1242
- $byteLength = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
1243
- $value = substr($this->_summaryInformation, $secOffset + 8 + $offset, $byteLength);
1244
- $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
1245
- $value = rtrim($value);
1246
- break;
1247
-
1248
- case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
1249
- // PHP-time
1250
- $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_summaryInformation, $secOffset + 4 + $offset, 8));
1251
- break;
1252
-
1253
- case 0x47: // Clipboard format
1254
- // not needed yet, fix later if necessary
1255
- break;
1256
- }
1257
-
1258
- switch ($id) {
1259
- case 0x01: // Code Page
1260
- $codePage = PHPExcel_Shared_CodePage::NumberToName($value);
1261
- break;
1262
-
1263
- case 0x02: // Title
1264
- $this->_phpExcel->getProperties()->setTitle($value);
1265
- break;
1266
-
1267
- case 0x03: // Subject
1268
- $this->_phpExcel->getProperties()->setSubject($value);
1269
- break;
1270
-
1271
- case 0x04: // Author (Creator)
1272
- $this->_phpExcel->getProperties()->setCreator($value);
1273
- break;
1274
-
1275
- case 0x05: // Keywords
1276
- $this->_phpExcel->getProperties()->setKeywords($value);
1277
- break;
1278
-
1279
- case 0x06: // Comments (Description)
1280
- $this->_phpExcel->getProperties()->setDescription($value);
1281
- break;
1282
-
1283
- case 0x07: // Template
1284
- // Not supported by PHPExcel
1285
- break;
1286
-
1287
- case 0x08: // Last Saved By (LastModifiedBy)
1288
- $this->_phpExcel->getProperties()->setLastModifiedBy($value);
1289
- break;
1290
-
1291
- case 0x09: // Revision
1292
- // Not supported by PHPExcel
1293
- break;
1294
-
1295
- case 0x0A: // Total Editing Time
1296
- // Not supported by PHPExcel
1297
- break;
1298
-
1299
- case 0x0B: // Last Printed
1300
- // Not supported by PHPExcel
1301
- break;
1302
-
1303
- case 0x0C: // Created Date/Time
1304
- $this->_phpExcel->getProperties()->setCreated($value);
1305
- break;
1306
-
1307
- case 0x0D: // Modified Date/Time
1308
- $this->_phpExcel->getProperties()->setModified($value);
1309
- break;
1310
-
1311
- case 0x0E: // Number of Pages
1312
- // Not supported by PHPExcel
1313
- break;
1314
-
1315
- case 0x0F: // Number of Words
1316
- // Not supported by PHPExcel
1317
- break;
1318
-
1319
- case 0x10: // Number of Characters
1320
- // Not supported by PHPExcel
1321
- break;
1322
-
1323
- case 0x11: // Thumbnail
1324
- // Not supported by PHPExcel
1325
- break;
1326
-
1327
- case 0x12: // Name of creating application
1328
- // Not supported by PHPExcel
1329
- break;
1330
-
1331
- case 0x13: // Security
1332
- // Not supported by PHPExcel
1333
- break;
1334
-
1335
- }
1336
- }
1337
- }
1338
-
1339
-
1340
- /**
1341
- * Read additional document summary information
1342
- */
1343
- private function _readDocumentSummaryInformation()
1344
- {
1345
- if (!isset($this->_documentSummaryInformation)) {
1346
- return;
1347
- }
1348
-
1349
- // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
1350
- // offset: 2; size: 2;
1351
- // offset: 4; size: 2; OS version
1352
- // offset: 6; size: 2; OS indicator
1353
- // offset: 8; size: 16
1354
- // offset: 24; size: 4; section count
1355
- $secCount = self::_GetInt4d($this->_documentSummaryInformation, 24);
1356
- // echo '$secCount = ',$secCount,'<br />';
1357
-
1358
- // offset: 28; size: 16; first section's class id: 02 d5 cd d5 9c 2e 1b 10 93 97 08 00 2b 2c f9 ae
1359
- // offset: 44; size: 4; first section offset
1360
- $secOffset = self::_GetInt4d($this->_documentSummaryInformation, 44);
1361
- // echo '$secOffset = ',$secOffset,'<br />';
1362
-
1363
- // section header
1364
- // offset: $secOffset; size: 4; section length
1365
- $secLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset);
1366
- // echo '$secLength = ',$secLength,'<br />';
1367
-
1368
- // offset: $secOffset+4; size: 4; property count
1369
- $countProperties = self::_GetInt4d($this->_documentSummaryInformation, $secOffset+4);
1370
- // echo '$countProperties = ',$countProperties,'<br />';
1371
-
1372
- // initialize code page (used to resolve string values)
1373
- $codePage = 'CP1252';
1374
-
1375
- // offset: ($secOffset+8); size: var
1376
- // loop through property decarations and properties
1377
- for ($i = 0; $i < $countProperties; ++$i) {
1378
- // echo 'Property ',$i,'<br />';
1379
- // offset: ($secOffset+8) + (8 * $i); size: 4; property ID
1380
- $id = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+8) + (8 * $i));
1381
- // echo 'ID is ',$id,'<br />';
1382
-
1383
- // Use value of property id as appropriate
1384
- // offset: 60 + 8 * $i; size: 4; offset from beginning of section (48)
1385
- $offset = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+12) + (8 * $i));
1386
-
1387
- $type = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + $offset);
1388
- // echo 'Type is ',$type,', ';
1389
-
1390
- // initialize property value
1391
- $value = null;
1392
-
1393
- // extract property value based on property type
1394
- switch ($type) {
1395
- case 0x02: // 2 byte signed integer
1396
- $value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1397
- break;
1398
-
1399
- case 0x03: // 4 byte signed integer
1400
- $value = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1401
- break;
1402
-
1403
- case 0x0B: // Boolean
1404
- $value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1405
- $value = ($value == 0 ? false : true);
1406
- break;
1407
-
1408
- case 0x13: // 4 byte unsigned integer
1409
- // not needed yet, fix later if necessary
1410
- break;
1411
-
1412
- case 0x1E: // null-terminated string prepended by dword string length
1413
- $byteLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1414
- $value = substr($this->_documentSummaryInformation, $secOffset + 8 + $offset, $byteLength);
1415
- $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
1416
- $value = rtrim($value);
1417
- break;
1418
-
1419
- case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
1420
- // PHP-Time
1421
- $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_documentSummaryInformation, $secOffset + 4 + $offset, 8));
1422
- break;
1423
-
1424
- case 0x47: // Clipboard format
1425
- // not needed yet, fix later if necessary
1426
- break;
1427
- }
1428
-
1429
- switch ($id) {
1430
- case 0x01: // Code Page
1431
- $codePage = PHPExcel_Shared_CodePage::NumberToName($value);
1432
- break;
1433
-
1434
- case 0x02: // Category
1435
- $this->_phpExcel->getProperties()->setCategory($value);
1436
- break;
1437
-
1438
- case 0x03: // Presentation Target
1439
- // Not supported by PHPExcel
1440
- break;
1441
-
1442
- case 0x04: // Bytes
1443
- // Not supported by PHPExcel
1444
- break;
1445
-
1446
- case 0x05: // Lines
1447
- // Not supported by PHPExcel
1448
- break;
1449
-
1450
- case 0x06: // Paragraphs
1451
- // Not supported by PHPExcel
1452
- break;
1453
-
1454
- case 0x07: // Slides
1455
- // Not supported by PHPExcel
1456
- break;
1457
-
1458
- case 0x08: // Notes
1459
- // Not supported by PHPExcel
1460
- break;
1461
-
1462
- case 0x09: // Hidden Slides
1463
- // Not supported by PHPExcel
1464
- break;
1465
-
1466
- case 0x0A: // MM Clips
1467
- // Not supported by PHPExcel
1468
- break;
1469
-
1470
- case 0x0B: // Scale Crop
1471
- // Not supported by PHPExcel
1472
- break;
1473
-
1474
- case 0x0C: // Heading Pairs
1475
- // Not supported by PHPExcel
1476
- break;
1477
-
1478
- case 0x0D: // Titles of Parts
1479
- // Not supported by PHPExcel
1480
- break;
1481
-
1482
- case 0x0E: // Manager
1483
- $this->_phpExcel->getProperties()->setManager($value);
1484
- break;
1485
-
1486
- case 0x0F: // Company
1487
- $this->_phpExcel->getProperties()->setCompany($value);
1488
- break;
1489
-
1490
- case 0x10: // Links up-to-date
1491
- // Not supported by PHPExcel
1492
- break;
1493
-
1494
- }
1495
- }
1496
- }
1497
-
1498
-
1499
- /**
1500
- * Reads a general type of BIFF record. Does nothing except for moving stream pointer forward to next record.
1501
- */
1502
- private function _readDefault()
1503
- {
1504
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1505
- // $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1506
-
1507
- // move stream pointer to next record
1508
- $this->_pos += 4 + $length;
1509
- }
1510
-
1511
-
1512
- /**
1513
- * The NOTE record specifies a comment associated with a particular cell. In Excel 95 (BIFF7) and earlier versions,
1514
- * this record stores a note (cell note). This feature was significantly enhanced in Excel 97.
1515
- */
1516
- private function _readNote()
1517
- {
1518
- // echo '<b>Read Cell Annotation</b><br />';
1519
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1520
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1521
-
1522
- // move stream pointer to next record
1523
- $this->_pos += 4 + $length;
1524
-
1525
- if ($this->_readDataOnly) {
1526
- return;
1527
- }
1528
-
1529
- $cellAddress = $this->_readBIFF8CellAddress(substr($recordData, 0, 4));
1530
- if ($this->_version == self::XLS_BIFF8) {
1531
- $noteObjID = self::_GetInt2d($recordData, 6);
1532
- $noteAuthor = self::_readUnicodeStringLong(substr($recordData, 8));
1533
- $noteAuthor = $noteAuthor['value'];
1534
- // echo 'Note Address=',$cellAddress,'<br />';
1535
- // echo 'Note Object ID=',$noteObjID,'<br />';
1536
- // echo 'Note Author=',$noteAuthor,'<hr />';
1537
- //
1538
- $this->_cellNotes[$noteObjID] = array('cellRef' => $cellAddress,
1539
- 'objectID' => $noteObjID,
1540
- 'author' => $noteAuthor
1541
- );
1542
- } else {
1543
- $extension = false;
1544
- if ($cellAddress == '$B$65536') {
1545
- // If the address row is -1 and the column is 0, (which translates as $B$65536) then this is a continuation
1546
- // note from the previous cell annotation. We're not yet handling this, so annotations longer than the
1547
- // max 2048 bytes will probably throw a wobbly.
1548
- $row = self::_GetInt2d($recordData, 0);
1549
- $extension = true;
1550
- $cellAddress = array_pop(array_keys($this->_phpSheet->getComments()));
1551
- }
1552
- // echo 'Note Address=',$cellAddress,'<br />';
1553
-
1554
- $cellAddress = str_replace('$','',$cellAddress);
1555
- $noteLength = self::_GetInt2d($recordData, 4);
1556
- $noteText = trim(substr($recordData, 6));
1557
- // echo 'Note Length=',$noteLength,'<br />';
1558
- // echo 'Note Text=',$noteText,'<br />';
1559
-
1560
- if ($extension) {
1561
- // Concatenate this extension with the currently set comment for the cell
1562
- $comment = $this->_phpSheet->getComment( $cellAddress );
1563
- $commentText = $comment->getText()->getPlainText();
1564
- $comment->setText($this->_parseRichText($commentText.$noteText) );
1565
- } else {
1566
- // Set comment for the cell
1567
- $this->_phpSheet->getComment( $cellAddress )
1568
- // ->setAuthor( $author )
1569
- ->setText($this->_parseRichText($noteText) );
1570
- }
1571
- }
1572
-
1573
- }
1574
-
1575
-
1576
- /**
1577
- * The TEXT Object record contains the text associated with a cell annotation.
1578
- */
1579
- private function _readTextObject()
1580
- {
1581
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1582
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1583
-
1584
- // move stream pointer to next record
1585
- $this->_pos += 4 + $length;
1586
-
1587
- if ($this->_readDataOnly) {
1588
- return;
1589
- }
1590
-
1591
- // recordData consists of an array of subrecords looking like this:
1592
- // grbit: 2 bytes; Option Flags
1593
- // rot: 2 bytes; rotation
1594
- // cchText: 2 bytes; length of the text (in the first continue record)
1595
- // cbRuns: 2 bytes; length of the formatting (in the second continue record)
1596
- // followed by the continuation records containing the actual text and formatting
1597
- $grbitOpts = self::_GetInt2d($recordData, 0);
1598
- $rot = self::_GetInt2d($recordData, 2);
1599
- $cchText = self::_GetInt2d($recordData, 10);
1600
- $cbRuns = self::_GetInt2d($recordData, 12);
1601
- $text = $this->_getSplicedRecordData();
1602
-
1603
- $this->_textObjects[$this->textObjRef] = array(
1604
- 'text' => substr($text["recordData"],$text["spliceOffsets"][0]+1,$cchText),
1605
- 'format' => substr($text["recordData"],$text["spliceOffsets"][1],$cbRuns),
1606
- 'alignment' => $grbitOpts,
1607
- 'rotation' => $rot
1608
- );
1609
-
1610
- // echo '<b>_readTextObject()</b><br />';
1611
- // var_dump($this->_textObjects[$this->textObjRef]);
1612
- // echo '<br />';
1613
- }
1614
-
1615
-
1616
- /**
1617
- * Read BOF
1618
- */
1619
- private function _readBof()
1620
- {
1621
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1622
- $recordData = substr($this->_data, $this->_pos + 4, $length);
1623
-
1624
- // move stream pointer to next record
1625
- $this->_pos += 4 + $length;
1626
-
1627
- // offset: 2; size: 2; type of the following data
1628
- $substreamType = self::_GetInt2d($recordData, 2);
1629
-
1630
- switch ($substreamType) {
1631
- case self::XLS_WorkbookGlobals:
1632
- $version = self::_GetInt2d($recordData, 0);
1633
- if (($version != self::XLS_BIFF8) && ($version != self::XLS_BIFF7)) {
1634
- throw new PHPExcel_Reader_Exception('Cannot read this Excel file. Version is too old.');
1635
- }
1636
- $this->_version = $version;
1637
- break;
1638
-
1639
- case self::XLS_Worksheet:
1640
- // do not use this version information for anything
1641
- // it is unreliable (OpenOffice doc, 5.8), use only version information from the global stream
1642
- break;
1643
-
1644
- default:
1645
- // substream, e.g. chart
1646
- // just skip the entire substream
1647
- do {
1648
- $code = self::_GetInt2d($this->_data, $this->_pos);
1649
- $this->_readDefault();
1650
- } while ($code != self::XLS_Type_EOF && $this->_pos < $this->_dataSize);
1651
- break;
1652
- }
1653
- }
1654
-
1655
-
1656
- /**
1657
- * FILEPASS
1658
- *
1659
- * This record is part of the File Protection Block. It
1660
- * contains information about the read/write password of the
1661
- * file. All record contents following this record will be
1662
- * encrypted.
1663
- *
1664
- * -- "OpenOffice.org's Documentation of the Microsoft
1665
- * Excel File Format"
1666
- *
1667
- * The decryption functions and objects used from here on in
1668
- * are based on the source of Spreadsheet-ParseExcel:
1669
- * http://search.cpan.org/~jmcnamara/Spreadsheet-ParseExcel/
1670
- */
1671
- private function _readFilepass()
1672
- {
1673
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1674
-
1675
- if ($length != 54) {
1676
- throw new PHPExcel_Reader_Exception('Unexpected file pass record length');
1677
- }
1678
-
1679
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1680
-
1681
- // move stream pointer to next record
1682
- $this->_pos += 4 + $length;
1683
-
1684
- if (!$this->_verifyPassword(
1685
- 'VelvetSweatshop',
1686
- substr($recordData, 6, 16),
1687
- substr($recordData, 22, 16),
1688
- substr($recordData, 38, 16),
1689
- $this->_md5Ctxt
1690
- )) {
1691
- throw new PHPExcel_Reader_Exception('Decryption password incorrect');
1692
- }
1693
-
1694
- $this->_encryption = self::MS_BIFF_CRYPTO_RC4;
1695
-
1696
- // Decryption required from the record after next onwards
1697
- $this->_encryptionStartPos = $this->_pos + self::_GetInt2d($this->_data, $this->_pos + 2);
1698
- }
1699
-
1700
- /**
1701
- * Make an RC4 decryptor for the given block
1702
- *
1703
- * @var int $block Block for which to create decrypto
1704
- * @var string $valContext MD5 context state
1705
- *
1706
- * @return PHPExcel_Reader_Excel5_RC4
1707
- */
1708
- private function _makeKey($block, $valContext)
1709
- {
1710
- $pwarray = str_repeat("\0", 64);
1711
-
1712
- for ($i = 0; $i < 5; $i++) {
1713
- $pwarray[$i] = $valContext[$i];
1714
- }
1715
-
1716
- $pwarray[5] = chr($block & 0xff);
1717
- $pwarray[6] = chr(($block >> 8) & 0xff);
1718
- $pwarray[7] = chr(($block >> 16) & 0xff);
1719
- $pwarray[8] = chr(($block >> 24) & 0xff);
1720
-
1721
- $pwarray[9] = "\x80";
1722
- $pwarray[56] = "\x48";
1723
-
1724
- $md5 = new PHPExcel_Reader_Excel5_MD5();
1725
- $md5->add($pwarray);
1726
-
1727
- $s = $md5->getContext();
1728
- return new PHPExcel_Reader_Excel5_RC4($s);
1729
- }
1730
-
1731
- /**
1732
- * Verify RC4 file password
1733
- *
1734
- * @var string $password Password to check
1735
- * @var string $docid Document id
1736
- * @var string $salt_data Salt data
1737
- * @var string $hashedsalt_data Hashed salt data
1738
- * @var string &$valContext Set to the MD5 context of the value
1739
- *
1740
- * @return bool Success
1741
- */
1742
- private function _verifyPassword($password, $docid, $salt_data, $hashedsalt_data, &$valContext)
1743
- {
1744
- $pwarray = str_repeat("\0", 64);
1745
-
1746
- for ($i = 0; $i < strlen($password); $i++) {
1747
- $o = ord(substr($password, $i, 1));
1748
- $pwarray[2 * $i] = chr($o & 0xff);
1749
- $pwarray[2 * $i + 1] = chr(($o >> 8) & 0xff);
1750
- }
1751
- $pwarray[2 * $i] = chr(0x80);
1752
- $pwarray[56] = chr(($i << 4) & 0xff);
1753
-
1754
- $md5 = new PHPExcel_Reader_Excel5_MD5();
1755
- $md5->add($pwarray);
1756
-
1757
- $mdContext1 = $md5->getContext();
1758
-
1759
- $offset = 0;
1760
- $keyoffset = 0;
1761
- $tocopy = 5;
1762
-
1763
- $md5->reset();
1764
-
1765
- while ($offset != 16) {
1766
- if ((64 - $offset) < 5) {
1767
- $tocopy = 64 - $offset;
1768
- }
1769
-
1770
- for ($i = 0; $i <= $tocopy; $i++) {
1771
- $pwarray[$offset + $i] = $mdContext1[$keyoffset + $i];
1772
- }
1773
-
1774
- $offset += $tocopy;
1775
-
1776
- if ($offset == 64) {
1777
- $md5->add($pwarray);
1778
- $keyoffset = $tocopy;
1779
- $tocopy = 5 - $tocopy;
1780
- $offset = 0;
1781
- continue;
1782
- }
1783
-
1784
- $keyoffset = 0;
1785
- $tocopy = 5;
1786
- for ($i = 0; $i < 16; $i++) {
1787
- $pwarray[$offset + $i] = $docid[$i];
1788
- }
1789
- $offset += 16;
1790
- }
1791
-
1792
- $pwarray[16] = "\x80";
1793
- for ($i = 0; $i < 47; $i++) {
1794
- $pwarray[17 + $i] = "\0";
1795
- }
1796
- $pwarray[56] = "\x80";
1797
- $pwarray[57] = "\x0a";
1798
-
1799
- $md5->add($pwarray);
1800
- $valContext = $md5->getContext();
1801
-
1802
- $key = $this->_makeKey(0, $valContext);
1803
-
1804
- $salt = $key->RC4($salt_data);
1805
- $hashedsalt = $key->RC4($hashedsalt_data);
1806
-
1807
- $salt .= "\x80" . str_repeat("\0", 47);
1808
- $salt[56] = "\x80";
1809
-
1810
- $md5->reset();
1811
- $md5->add($salt);
1812
- $mdContext2 = $md5->getContext();
1813
-
1814
- return $mdContext2 == $hashedsalt;
1815
- }
1816
-
1817
- /**
1818
- * CODEPAGE
1819
- *
1820
- * This record stores the text encoding used to write byte
1821
- * strings, stored as MS Windows code page identifier.
1822
- *
1823
- * -- "OpenOffice.org's Documentation of the Microsoft
1824
- * Excel File Format"
1825
- */
1826
- private function _readCodepage()
1827
- {
1828
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1829
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1830
-
1831
- // move stream pointer to next record
1832
- $this->_pos += 4 + $length;
1833
-
1834
- // offset: 0; size: 2; code page identifier
1835
- $codepage = self::_GetInt2d($recordData, 0);
1836
-
1837
- $this->_codepage = PHPExcel_Shared_CodePage::NumberToName($codepage);
1838
- }
1839
-
1840
-
1841
- /**
1842
- * DATEMODE
1843
- *
1844
- * This record specifies the base date for displaying date
1845
- * values. All dates are stored as count of days past this
1846
- * base date. In BIFF2-BIFF4 this record is part of the
1847
- * Calculation Settings Block. In BIFF5-BIFF8 it is
1848
- * stored in the Workbook Globals Substream.
1849
- *
1850
- * -- "OpenOffice.org's Documentation of the Microsoft
1851
- * Excel File Format"
1852
- */
1853
- private function _readDateMode()
1854
- {
1855
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1856
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1857
-
1858
- // move stream pointer to next record
1859
- $this->_pos += 4 + $length;
1860
-
1861
- // offset: 0; size: 2; 0 = base 1900, 1 = base 1904
1862
- PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900);
1863
- if (ord($recordData{0}) == 1) {
1864
- PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_MAC_1904);
1865
- }
1866
- }
1867
-
1868
-
1869
- /**
1870
- * Read a FONT record
1871
- */
1872
- private function _readFont()
1873
- {
1874
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1875
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1876
-
1877
- // move stream pointer to next record
1878
- $this->_pos += 4 + $length;
1879
-
1880
- if (!$this->_readDataOnly) {
1881
- $objFont = new PHPExcel_Style_Font();
1882
-
1883
- // offset: 0; size: 2; height of the font (in twips = 1/20 of a point)
1884
- $size = self::_GetInt2d($recordData, 0);
1885
- $objFont->setSize($size / 20);
1886
-
1887
- // offset: 2; size: 2; option flags
1888
- // bit: 0; mask 0x0001; bold (redundant in BIFF5-BIFF8)
1889
- // bit: 1; mask 0x0002; italic
1890
- $isItalic = (0x0002 & self::_GetInt2d($recordData, 2)) >> 1;
1891
- if ($isItalic) $objFont->setItalic(true);
1892
-
1893
- // bit: 2; mask 0x0004; underlined (redundant in BIFF5-BIFF8)
1894
- // bit: 3; mask 0x0008; strike
1895
- $isStrike = (0x0008 & self::_GetInt2d($recordData, 2)) >> 3;
1896
- if ($isStrike) $objFont->setStrikethrough(true);
1897
-
1898
- // offset: 4; size: 2; colour index
1899
- $colorIndex = self::_GetInt2d($recordData, 4);
1900
- $objFont->colorIndex = $colorIndex;
1901
-
1902
- // offset: 6; size: 2; font weight
1903
- $weight = self::_GetInt2d($recordData, 6);
1904
- switch ($weight) {
1905
- case 0x02BC:
1906
- $objFont->setBold(true);
1907
- break;
1908
- }
1909
-
1910
- // offset: 8; size: 2; escapement type
1911
- $escapement = self::_GetInt2d($recordData, 8);
1912
- switch ($escapement) {
1913
- case 0x0001:
1914
- $objFont->setSuperScript(true);
1915
- break;
1916
- case 0x0002:
1917
- $objFont->setSubScript(true);
1918
- break;
1919
- }
1920
-
1921
- // offset: 10; size: 1; underline type
1922
- $underlineType = ord($recordData{10});
1923
- switch ($underlineType) {
1924
- case 0x00:
1925
- break; // no underline
1926
- case 0x01:
1927
- $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
1928
- break;
1929
- case 0x02:
1930
- $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLE);
1931
- break;
1932
- case 0x21:
1933
- $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING);
1934
- break;
1935
- case 0x22:
1936
- $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING);
1937
- break;
1938
- }
1939
-
1940
- // offset: 11; size: 1; font family
1941
- // offset: 12; size: 1; character set
1942
- // offset: 13; size: 1; not used
1943
- // offset: 14; size: var; font name
1944
- if ($this->_version == self::XLS_BIFF8) {
1945
- $string = self::_readUnicodeStringShort(substr($recordData, 14));
1946
- } else {
1947
- $string = $this->_readByteStringShort(substr($recordData, 14));
1948
- }
1949
- $objFont->setName($string['value']);
1950
-
1951
- $this->_objFonts[] = $objFont;
1952
- }
1953
- }
1954
-
1955
-
1956
- /**
1957
- * FORMAT
1958
- *
1959
- * This record contains information about a number format.
1960
- * All FORMAT records occur together in a sequential list.
1961
- *
1962
- * In BIFF2-BIFF4 other records referencing a FORMAT record
1963
- * contain a zero-based index into this list. From BIFF5 on
1964
- * the FORMAT record contains the index itself that will be
1965
- * used by other records.
1966
- *
1967
- * -- "OpenOffice.org's Documentation of the Microsoft
1968
- * Excel File Format"
1969
- */
1970
- private function _readFormat()
1971
- {
1972
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1973
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1974
-
1975
- // move stream pointer to next record
1976
- $this->_pos += 4 + $length;
1977
-
1978
- if (!$this->_readDataOnly) {
1979
- $indexCode = self::_GetInt2d($recordData, 0);
1980
-
1981
- if ($this->_version == self::XLS_BIFF8) {
1982
- $string = self::_readUnicodeStringLong(substr($recordData, 2));
1983
- } else {
1984
- // BIFF7
1985
- $string = $this->_readByteStringShort(substr($recordData, 2));
1986
- }
1987
-
1988
- $formatString = $string['value'];
1989
- $this->_formats[$indexCode] = $formatString;
1990
- }
1991
- }
1992
-
1993
-
1994
- /**
1995
- * XF - Extended Format
1996
- *
1997
- * This record contains formatting information for cells, rows, columns or styles.
1998
- * According to http://support.microsoft.com/kb/147732 there are always at least 15 cell style XF
1999
- * and 1 cell XF.
2000
- * Inspection of Excel files generated by MS Office Excel shows that XF records 0-14 are cell style XF
2001
- * and XF record 15 is a cell XF
2002
- * We only read the first cell style XF and skip the remaining cell style XF records
2003
- * We read all cell XF records.
2004
- *
2005
- * -- "OpenOffice.org's Documentation of the Microsoft
2006
- * Excel File Format"
2007
- */
2008
- private function _readXf()
2009
- {
2010
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2011
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2012
-
2013
- // move stream pointer to next record
2014
- $this->_pos += 4 + $length;
2015
-
2016
- $objStyle = new PHPExcel_Style();
2017
-
2018
- if (!$this->_readDataOnly) {
2019
- // offset: 0; size: 2; Index to FONT record
2020
- if (self::_GetInt2d($recordData, 0) < 4) {
2021
- $fontIndex = self::_GetInt2d($recordData, 0);
2022
- } else {
2023
- // this has to do with that index 4 is omitted in all BIFF versions for some strange reason
2024
- // check the OpenOffice documentation of the FONT record
2025
- $fontIndex = self::_GetInt2d($recordData, 0) - 1;
2026
- }
2027
- $objStyle->setFont($this->_objFonts[$fontIndex]);
2028
-
2029
- // offset: 2; size: 2; Index to FORMAT record
2030
- $numberFormatIndex = self::_GetInt2d($recordData, 2);
2031
- if (isset($this->_formats[$numberFormatIndex])) {
2032
- // then we have user-defined format code
2033
- $numberformat = array('code' => $this->_formats[$numberFormatIndex]);
2034
- } elseif (($code = PHPExcel_Style_NumberFormat::builtInFormatCode($numberFormatIndex)) !== '') {
2035
- // then we have built-in format code
2036
- $numberformat = array('code' => $code);
2037
- } else {
2038
- // we set the general format code
2039
- $numberformat = array('code' => 'General');
2040
- }
2041
- $objStyle->getNumberFormat()->setFormatCode($numberformat['code']);
2042
-
2043
- // offset: 4; size: 2; XF type, cell protection, and parent style XF
2044
- // bit 2-0; mask 0x0007; XF_TYPE_PROT
2045
- $xfTypeProt = self::_GetInt2d($recordData, 4);
2046
- // bit 0; mask 0x01; 1 = cell is locked
2047
- $isLocked = (0x01 & $xfTypeProt) >> 0;
2048
- $objStyle->getProtection()->setLocked($isLocked ?
2049
- PHPExcel_Style_Protection::PROTECTION_INHERIT : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
2050
-
2051
- // bit 1; mask 0x02; 1 = Formula is hidden
2052
- $isHidden = (0x02 & $xfTypeProt) >> 1;
2053
- $objStyle->getProtection()->setHidden($isHidden ?
2054
- PHPExcel_Style_Protection::PROTECTION_PROTECTED : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
2055
-
2056
- // bit 2; mask 0x04; 0 = Cell XF, 1 = Cell Style XF
2057
- $isCellStyleXf = (0x04 & $xfTypeProt) >> 2;
2058
-
2059
- // offset: 6; size: 1; Alignment and text break
2060
- // bit 2-0, mask 0x07; horizontal alignment
2061
- $horAlign = (0x07 & ord($recordData{6})) >> 0;
2062
- switch ($horAlign) {
2063
- case 0:
2064
- $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_GENERAL);
2065
- break;
2066
- case 1:
2067
- $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
2068
- break;
2069
- case 2:
2070
- $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
2071
- break;
2072
- case 3:
2073
- $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
2074
- break;
2075
- case 4:
2076
- $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_FILL);
2077
- break;
2078
- case 5:
2079
- $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY);
2080
- break;
2081
- case 6:
2082
- $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS);
2083
- break;
2084
- }
2085
- // bit 3, mask 0x08; wrap text
2086
- $wrapText = (0x08 & ord($recordData{6})) >> 3;
2087
- switch ($wrapText) {
2088
- case 0:
2089
- $objStyle->getAlignment()->setWrapText(false);
2090
- break;
2091
- case 1:
2092
- $objStyle->getAlignment()->setWrapText(true);
2093
- break;
2094
- }
2095
- // bit 6-4, mask 0x70; vertical alignment
2096
- $vertAlign = (0x70 & ord($recordData{6})) >> 4;
2097
- switch ($vertAlign) {
2098
- case 0:
2099
- $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_TOP);
2100
- break;
2101
- case 1:
2102
- $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
2103
- break;
2104
- case 2:
2105
- $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_BOTTOM);
2106
- break;
2107
- case 3:
2108
- $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_JUSTIFY);
2109
- break;
2110
- }
2111
-
2112
- if ($this->_version == self::XLS_BIFF8) {
2113
- // offset: 7; size: 1; XF_ROTATION: Text rotation angle
2114
- $angle = ord($recordData{7});
2115
- $rotation = 0;
2116
- if ($angle <= 90) {
2117
- $rotation = $angle;
2118
- } else if ($angle <= 180) {
2119
- $rotation = 90 - $angle;
2120
- } else if ($angle == 255) {
2121
- $rotation = -165;
2122
- }
2123
- $objStyle->getAlignment()->setTextRotation($rotation);
2124
-
2125
- // offset: 8; size: 1; Indentation, shrink to cell size, and text direction
2126
- // bit: 3-0; mask: 0x0F; indent level
2127
- $indent = (0x0F & ord($recordData{8})) >> 0;
2128
- $objStyle->getAlignment()->setIndent($indent);
2129
-
2130
- // bit: 4; mask: 0x10; 1 = shrink content to fit into cell
2131
- $shrinkToFit = (0x10 & ord($recordData{8})) >> 4;
2132
- switch ($shrinkToFit) {
2133
- case 0:
2134
- $objStyle->getAlignment()->setShrinkToFit(false);
2135
- break;
2136
- case 1:
2137
- $objStyle->getAlignment()->setShrinkToFit(true);
2138
- break;
2139
- }
2140
-
2141
- // offset: 9; size: 1; Flags used for attribute groups
2142
-
2143
- // offset: 10; size: 4; Cell border lines and background area
2144
- // bit: 3-0; mask: 0x0000000F; left style
2145
- if ($bordersLeftStyle = self::_mapBorderStyle((0x0000000F & self::_GetInt4d($recordData, 10)) >> 0)) {
2146
- $objStyle->getBorders()->getLeft()->setBorderStyle($bordersLeftStyle);
2147
- }
2148
- // bit: 7-4; mask: 0x000000F0; right style
2149
- if ($bordersRightStyle = self::_mapBorderStyle((0x000000F0 & self::_GetInt4d($recordData, 10)) >> 4)) {
2150
- $objStyle->getBorders()->getRight()->setBorderStyle($bordersRightStyle);
2151
- }
2152
- // bit: 11-8; mask: 0x00000F00; top style
2153
- if ($bordersTopStyle = self::_mapBorderStyle((0x00000F00 & self::_GetInt4d($recordData, 10)) >> 8)) {
2154
- $objStyle->getBorders()->getTop()->setBorderStyle($bordersTopStyle);
2155
- }
2156
- // bit: 15-12; mask: 0x0000F000; bottom style
2157
- if ($bordersBottomStyle = self::_mapBorderStyle((0x0000F000 & self::_GetInt4d($recordData, 10)) >> 12)) {
2158
- $objStyle->getBorders()->getBottom()->setBorderStyle($bordersBottomStyle);
2159
- }
2160
- // bit: 22-16; mask: 0x007F0000; left color
2161
- $objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & self::_GetInt4d($recordData, 10)) >> 16;
2162
-
2163
- // bit: 29-23; mask: 0x3F800000; right color
2164
- $objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & self::_GetInt4d($recordData, 10)) >> 23;
2165
-
2166
- // bit: 30; mask: 0x40000000; 1 = diagonal line from top left to right bottom
2167
- $diagonalDown = (0x40000000 & self::_GetInt4d($recordData, 10)) >> 30 ?
2168
- true : false;
2169
-
2170
- // bit: 31; mask: 0x80000000; 1 = diagonal line from bottom left to top right
2171
- $diagonalUp = (0x80000000 & self::_GetInt4d($recordData, 10)) >> 31 ?
2172
- true : false;
2173
-
2174
- if ($diagonalUp == false && $diagonalDown == false) {
2175
- $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_NONE);
2176
- } elseif ($diagonalUp == true && $diagonalDown == false) {
2177
- $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_UP);
2178
- } elseif ($diagonalUp == false && $diagonalDown == true) {
2179
- $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_DOWN);
2180
- } elseif ($diagonalUp == true && $diagonalDown == true) {
2181
- $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_BOTH);
2182
- }
2183
-
2184
- // offset: 14; size: 4;
2185
- // bit: 6-0; mask: 0x0000007F; top color
2186
- $objStyle->getBorders()->getTop()->colorIndex = (0x0000007F & self::_GetInt4d($recordData, 14)) >> 0;
2187
-
2188
- // bit: 13-7; mask: 0x00003F80; bottom color
2189
- $objStyle->getBorders()->getBottom()->colorIndex = (0x00003F80 & self::_GetInt4d($recordData, 14)) >> 7;
2190
-
2191
- // bit: 20-14; mask: 0x001FC000; diagonal color
2192
- $objStyle->getBorders()->getDiagonal()->colorIndex = (0x001FC000 & self::_GetInt4d($recordData, 14)) >> 14;
2193
-
2194
- // bit: 24-21; mask: 0x01E00000; diagonal style
2195
- if ($bordersDiagonalStyle = self::_mapBorderStyle((0x01E00000 & self::_GetInt4d($recordData, 14)) >> 21)) {
2196
- $objStyle->getBorders()->getDiagonal()->setBorderStyle($bordersDiagonalStyle);
2197
- }
2198
-
2199
- // bit: 31-26; mask: 0xFC000000 fill pattern
2200
- if ($fillType = self::_mapFillPattern((0xFC000000 & self::_GetInt4d($recordData, 14)) >> 26)) {
2201
- $objStyle->getFill()->setFillType($fillType);
2202
- }
2203
- // offset: 18; size: 2; pattern and background colour
2204
- // bit: 6-0; mask: 0x007F; color index for pattern color
2205
- $objStyle->getFill()->startcolorIndex = (0x007F & self::_GetInt2d($recordData, 18)) >> 0;
2206
-
2207
- // bit: 13-7; mask: 0x3F80; color index for pattern background
2208
- $objStyle->getFill()->endcolorIndex = (0x3F80 & self::_GetInt2d($recordData, 18)) >> 7;
2209
- } else {
2210
- // BIFF5
2211
-
2212
- // offset: 7; size: 1; Text orientation and flags
2213
- $orientationAndFlags = ord($recordData{7});
2214
-
2215
- // bit: 1-0; mask: 0x03; XF_ORIENTATION: Text orientation
2216
- $xfOrientation = (0x03 & $orientationAndFlags) >> 0;
2217
- switch ($xfOrientation) {
2218
- case 0:
2219
- $objStyle->getAlignment()->setTextRotation(0);
2220
- break;
2221
- case 1:
2222
- $objStyle->getAlignment()->setTextRotation(-165);
2223
- break;
2224
- case 2:
2225
- $objStyle->getAlignment()->setTextRotation(90);
2226
- break;
2227
- case 3:
2228
- $objStyle->getAlignment()->setTextRotation(-90);
2229
- break;
2230
- }
2231
-
2232
- // offset: 8; size: 4; cell border lines and background area
2233
- $borderAndBackground = self::_GetInt4d($recordData, 8);
2234
-
2235
- // bit: 6-0; mask: 0x0000007F; color index for pattern color
2236
- $objStyle->getFill()->startcolorIndex = (0x0000007F & $borderAndBackground) >> 0;
2237
-
2238
- // bit: 13-7; mask: 0x00003F80; color index for pattern background
2239
- $objStyle->getFill()->endcolorIndex = (0x00003F80 & $borderAndBackground) >> 7;
2240
-
2241
- // bit: 21-16; mask: 0x003F0000; fill pattern
2242
- $objStyle->getFill()->setFillType(self::_mapFillPattern((0x003F0000 & $borderAndBackground) >> 16));
2243
-
2244
- // bit: 24-22; mask: 0x01C00000; bottom line style
2245
- $objStyle->getBorders()->getBottom()->setBorderStyle(self::_mapBorderStyle((0x01C00000 & $borderAndBackground) >> 22));
2246
-
2247
- // bit: 31-25; mask: 0xFE000000; bottom line color
2248
- $objStyle->getBorders()->getBottom()->colorIndex = (0xFE000000 & $borderAndBackground) >> 25;
2249
-
2250
- // offset: 12; size: 4; cell border lines
2251
- $borderLines = self::_GetInt4d($recordData, 12);
2252
-
2253
- // bit: 2-0; mask: 0x00000007; top line style
2254
- $objStyle->getBorders()->getTop()->setBorderStyle(self::_mapBorderStyle((0x00000007 & $borderLines) >> 0));
2255
-
2256
- // bit: 5-3; mask: 0x00000038; left line style
2257
- $objStyle->getBorders()->getLeft()->setBorderStyle(self::_mapBorderStyle((0x00000038 & $borderLines) >> 3));
2258
-
2259
- // bit: 8-6; mask: 0x000001C0; right line style
2260
- $objStyle->getBorders()->getRight()->setBorderStyle(self::_mapBorderStyle((0x000001C0 & $borderLines) >> 6));
2261
-
2262
- // bit: 15-9; mask: 0x0000FE00; top line color index
2263
- $objStyle->getBorders()->getTop()->colorIndex = (0x0000FE00 & $borderLines) >> 9;
2264
-
2265
- // bit: 22-16; mask: 0x007F0000; left line color index
2266
- $objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & $borderLines) >> 16;
2267
-
2268
- // bit: 29-23; mask: 0x3F800000; right line color index
2269
- $objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & $borderLines) >> 23;
2270
- }
2271
-
2272
- // add cellStyleXf or cellXf and update mapping
2273
- if ($isCellStyleXf) {
2274
- // we only read one style XF record which is always the first
2275
- if ($this->_xfIndex == 0) {
2276
- $this->_phpExcel->addCellStyleXf($objStyle);
2277
- $this->_mapCellStyleXfIndex[$this->_xfIndex] = 0;
2278
- }
2279
- } else {
2280
- // we read all cell XF records
2281
- $this->_phpExcel->addCellXf($objStyle);
2282
- $this->_mapCellXfIndex[$this->_xfIndex] = count($this->_phpExcel->getCellXfCollection()) - 1;
2283
- }
2284
-
2285
- // update XF index for when we read next record
2286
- ++$this->_xfIndex;
2287
- }
2288
- }
2289
-
2290
-
2291
- /**
2292
- *
2293
- */
2294
- private function _readXfExt()
2295
- {
2296
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2297
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2298
-
2299
- // move stream pointer to next record
2300
- $this->_pos += 4 + $length;
2301
-
2302
- if (!$this->_readDataOnly) {
2303
- // offset: 0; size: 2; 0x087D = repeated header
2304
-
2305
- // offset: 2; size: 2
2306
-
2307
- // offset: 4; size: 8; not used
2308
-
2309
- // offset: 12; size: 2; record version
2310
-
2311
- // offset: 14; size: 2; index to XF record which this record modifies
2312
- $ixfe = self::_GetInt2d($recordData, 14);
2313
-
2314
- // offset: 16; size: 2; not used
2315
-
2316
- // offset: 18; size: 2; number of extension properties that follow
2317
- $cexts = self::_GetInt2d($recordData, 18);
2318
-
2319
- // start reading the actual extension data
2320
- $offset = 20;
2321
- while ($offset < $length) {
2322
- // extension type
2323
- $extType = self::_GetInt2d($recordData, $offset);
2324
-
2325
- // extension length
2326
- $cb = self::_GetInt2d($recordData, $offset + 2);
2327
-
2328
- // extension data
2329
- $extData = substr($recordData, $offset + 4, $cb);
2330
-
2331
- switch ($extType) {
2332
- case 4: // fill start color
2333
- $xclfType = self::_GetInt2d($extData, 0); // color type
2334
- $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2335
-
2336
- if ($xclfType == 2) {
2337
- $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2338
-
2339
- // modify the relevant style property
2340
- if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2341
- $fill = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFill();
2342
- $fill->getStartColor()->setRGB($rgb);
2343
- unset($fill->startcolorIndex); // normal color index does not apply, discard
2344
- }
2345
- }
2346
- break;
2347
-
2348
- case 5: // fill end color
2349
- $xclfType = self::_GetInt2d($extData, 0); // color type
2350
- $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2351
-
2352
- if ($xclfType == 2) {
2353
- $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2354
-
2355
- // modify the relevant style property
2356
- if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2357
- $fill = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFill();
2358
- $fill->getEndColor()->setRGB($rgb);
2359
- unset($fill->endcolorIndex); // normal color index does not apply, discard
2360
- }
2361
- }
2362
- break;
2363
-
2364
- case 7: // border color top
2365
- $xclfType = self::_GetInt2d($extData, 0); // color type
2366
- $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2367
-
2368
- if ($xclfType == 2) {
2369
- $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2370
-
2371
- // modify the relevant style property
2372
- if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2373
- $top = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getTop();
2374
- $top->getColor()->setRGB($rgb);
2375
- unset($top->colorIndex); // normal color index does not apply, discard
2376
- }
2377
- }
2378
- break;
2379
-
2380
- case 8: // border color bottom
2381
- $xclfType = self::_GetInt2d($extData, 0); // color type
2382
- $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2383
-
2384
- if ($xclfType == 2) {
2385
- $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2386
-
2387
- // modify the relevant style property
2388
- if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2389
- $bottom = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getBottom();
2390
- $bottom->getColor()->setRGB($rgb);
2391
- unset($bottom->colorIndex); // normal color index does not apply, discard
2392
- }
2393
- }
2394
- break;
2395
-
2396
- case 9: // border color left
2397
- $xclfType = self::_GetInt2d($extData, 0); // color type
2398
- $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2399
-
2400
- if ($xclfType == 2) {
2401
- $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2402
-
2403
- // modify the relevant style property
2404
- if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2405
- $left = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getLeft();
2406
- $left->getColor()->setRGB($rgb);
2407
- unset($left->colorIndex); // normal color index does not apply, discard
2408
- }
2409
- }
2410
- break;
2411
-
2412
- case 10: // border color right
2413
- $xclfType = self::_GetInt2d($extData, 0); // color type
2414
- $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2415
-
2416
- if ($xclfType == 2) {
2417
- $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2418
-
2419
- // modify the relevant style property
2420
- if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2421
- $right = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getRight();
2422
- $right->getColor()->setRGB($rgb);
2423
- unset($right->colorIndex); // normal color index does not apply, discard
2424
- }
2425
- }
2426
- break;
2427
-
2428
- case 11: // border color diagonal
2429
- $xclfType = self::_GetInt2d($extData, 0); // color type
2430
- $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2431
-
2432
- if ($xclfType == 2) {
2433
- $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2434
-
2435
- // modify the relevant style property
2436
- if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2437
- $diagonal = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getDiagonal();
2438
- $diagonal->getColor()->setRGB($rgb);
2439
- unset($diagonal->colorIndex); // normal color index does not apply, discard
2440
- }
2441
- }
2442
- break;
2443
-
2444
- case 13: // font color
2445
- $xclfType = self::_GetInt2d($extData, 0); // color type
2446
- $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2447
-
2448
- if ($xclfType == 2) {
2449
- $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2450
-
2451
- // modify the relevant style property
2452
- if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2453
- $font = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFont();
2454
- $font->getColor()->setRGB($rgb);
2455
- unset($font->colorIndex); // normal color index does not apply, discard
2456
- }
2457
- }
2458
- break;
2459
- }
2460
-
2461
- $offset += $cb;
2462
- }
2463
- }
2464
-
2465
- }
2466
-
2467
-
2468
- /**
2469
- * Read STYLE record
2470
- */
2471
- private function _readStyle()
2472
- {
2473
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2474
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2475
-
2476
- // move stream pointer to next record
2477
- $this->_pos += 4 + $length;
2478
-
2479
- if (!$this->_readDataOnly) {
2480
- // offset: 0; size: 2; index to XF record and flag for built-in style
2481
- $ixfe = self::_GetInt2d($recordData, 0);
2482
-
2483
- // bit: 11-0; mask 0x0FFF; index to XF record
2484
- $xfIndex = (0x0FFF & $ixfe) >> 0;
2485
-
2486
- // bit: 15; mask 0x8000; 0 = user-defined style, 1 = built-in style
2487
- $isBuiltIn = (bool) ((0x8000 & $ixfe) >> 15);
2488
-
2489
- if ($isBuiltIn) {
2490
- // offset: 2; size: 1; identifier for built-in style
2491
- $builtInId = ord($recordData{2});
2492
-
2493
- switch ($builtInId) {
2494
- case 0x00:
2495
- // currently, we are not using this for anything
2496
- break;
2497
-
2498
- default:
2499
- break;
2500
- }
2501
-
2502
- } else {
2503
- // user-defined; not supported by PHPExcel
2504
- }
2505
- }
2506
- }
2507
-
2508
-
2509
- /**
2510
- * Read PALETTE record
2511
- */
2512
- private function _readPalette()
2513
- {
2514
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2515
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2516
-
2517
- // move stream pointer to next record
2518
- $this->_pos += 4 + $length;
2519
-
2520
- if (!$this->_readDataOnly) {
2521
- // offset: 0; size: 2; number of following colors
2522
- $nm = self::_GetInt2d($recordData, 0);
2523
-
2524
- // list of RGB colors
2525
- for ($i = 0; $i < $nm; ++$i) {
2526
- $rgb = substr($recordData, 2 + 4 * $i, 4);
2527
- $this->_palette[] = self::_readRGB($rgb);
2528
- }
2529
- }
2530
- }
2531
-
2532
-
2533
- /**
2534
- * SHEET
2535
- *
2536
- * This record is located in the Workbook Globals
2537
- * Substream and represents a sheet inside the workbook.
2538
- * One SHEET record is written for each sheet. It stores the
2539
- * sheet name and a stream offset to the BOF record of the
2540
- * respective Sheet Substream within the Workbook Stream.
2541
- *
2542
- * -- "OpenOffice.org's Documentation of the Microsoft
2543
- * Excel File Format"
2544
- */
2545
- private function _readSheet()
2546
- {
2547
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2548
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2549
-
2550
- // offset: 0; size: 4; absolute stream position of the BOF record of the sheet
2551
- // NOTE: not encrypted
2552
- $rec_offset = self::_GetInt4d($this->_data, $this->_pos + 4);
2553
-
2554
- // move stream pointer to next record
2555
- $this->_pos += 4 + $length;
2556
-
2557
- // offset: 4; size: 1; sheet state
2558
- switch (ord($recordData{4})) {
2559
- case 0x00: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE; break;
2560
- case 0x01: $sheetState = PHPExcel_Worksheet::SHEETSTATE_HIDDEN; break;
2561
- case 0x02: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VERYHIDDEN; break;
2562
- default: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE; break;
2563
- }
2564
-
2565
- // offset: 5; size: 1; sheet type
2566
- $sheetType = ord($recordData{5});
2567
-
2568
- // offset: 6; size: var; sheet name
2569
- if ($this->_version == self::XLS_BIFF8) {
2570
- $string = self::_readUnicodeStringShort(substr($recordData, 6));
2571
- $rec_name = $string['value'];
2572
- } elseif ($this->_version == self::XLS_BIFF7) {
2573
- $string = $this->_readByteStringShort(substr($recordData, 6));
2574
- $rec_name = $string['value'];
2575
- }
2576
-
2577
- $this->_sheets[] = array(
2578
- 'name' => $rec_name,
2579
- 'offset' => $rec_offset,
2580
- 'sheetState' => $sheetState,
2581
- 'sheetType' => $sheetType,
2582
- );
2583
- }
2584
-
2585
-
2586
- /**
2587
- * Read EXTERNALBOOK record
2588
- */
2589
- private function _readExternalBook()
2590
- {
2591
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2592
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2593
-
2594
- // move stream pointer to next record
2595
- $this->_pos += 4 + $length;
2596
-
2597
- // offset within record data
2598
- $offset = 0;
2599
-
2600
- // there are 4 types of records
2601
- if (strlen($recordData) > 4) {
2602
- // external reference
2603
- // offset: 0; size: 2; number of sheet names ($nm)
2604
- $nm = self::_GetInt2d($recordData, 0);
2605
- $offset += 2;
2606
-
2607
- // offset: 2; size: var; encoded URL without sheet name (Unicode string, 16-bit length)
2608
- $encodedUrlString = self::_readUnicodeStringLong(substr($recordData, 2));
2609
- $offset += $encodedUrlString['size'];
2610
-
2611
- // offset: var; size: var; list of $nm sheet names (Unicode strings, 16-bit length)
2612
- $externalSheetNames = array();
2613
- for ($i = 0; $i < $nm; ++$i) {
2614
- $externalSheetNameString = self::_readUnicodeStringLong(substr($recordData, $offset));
2615
- $externalSheetNames[] = $externalSheetNameString['value'];
2616
- $offset += $externalSheetNameString['size'];
2617
- }
2618
-
2619
- // store the record data
2620
- $this->_externalBooks[] = array(
2621
- 'type' => 'external',
2622
- 'encodedUrl' => $encodedUrlString['value'],
2623
- 'externalSheetNames' => $externalSheetNames,
2624
- );
2625
-
2626
- } elseif (substr($recordData, 2, 2) == pack('CC', 0x01, 0x04)) {
2627
- // internal reference
2628
- // offset: 0; size: 2; number of sheet in this document
2629
- // offset: 2; size: 2; 0x01 0x04
2630
- $this->_externalBooks[] = array(
2631
- 'type' => 'internal',
2632
- );
2633
- } elseif (substr($recordData, 0, 4) == pack('vCC', 0x0001, 0x01, 0x3A)) {
2634
- // add-in function
2635
- // offset: 0; size: 2; 0x0001
2636
- $this->_externalBooks[] = array(
2637
- 'type' => 'addInFunction',
2638
- );
2639
- } elseif (substr($recordData, 0, 2) == pack('v', 0x0000)) {
2640
- // DDE links, OLE links
2641
- // offset: 0; size: 2; 0x0000
2642
- // offset: 2; size: var; encoded source document name
2643
- $this->_externalBooks[] = array(
2644
- 'type' => 'DDEorOLE',
2645
- );
2646
- }
2647
- }
2648
-
2649
-
2650
- /**
2651
- * Read EXTERNNAME record.
2652
- */
2653
- private function _readExternName()
2654
- {
2655
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2656
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2657
-
2658
- // move stream pointer to next record
2659
- $this->_pos += 4 + $length;
2660
-
2661
- // external sheet references provided for named cells
2662
- if ($this->_version == self::XLS_BIFF8) {
2663
- // offset: 0; size: 2; options
2664
- $options = self::_GetInt2d($recordData, 0);
2665
-
2666
- // offset: 2; size: 2;
2667
-
2668
- // offset: 4; size: 2; not used
2669
-
2670
- // offset: 6; size: var
2671
- $nameString = self::_readUnicodeStringShort(substr($recordData, 6));
2672
-
2673
- // offset: var; size: var; formula data
2674
- $offset = 6 + $nameString['size'];
2675
- $formula = $this->_getFormulaFromStructure(substr($recordData, $offset));
2676
-
2677
- $this->_externalNames[] = array(
2678
- 'name' => $nameString['value'],
2679
- 'formula' => $formula,
2680
- );
2681
- }
2682
- }
2683
-
2684
-
2685
- /**
2686
- * Read EXTERNSHEET record
2687
- */
2688
- private function _readExternSheet()
2689
- {
2690
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2691
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2692
-
2693
- // move stream pointer to next record
2694
- $this->_pos += 4 + $length;
2695
-
2696
- // external sheet references provided for named cells
2697
- if ($this->_version == self::XLS_BIFF8) {
2698
- // offset: 0; size: 2; number of following ref structures
2699
- $nm = self::_GetInt2d($recordData, 0);
2700
- for ($i = 0; $i < $nm; ++$i) {
2701
- $this->_ref[] = array(
2702
- // offset: 2 + 6 * $i; index to EXTERNALBOOK record
2703
- 'externalBookIndex' => self::_GetInt2d($recordData, 2 + 6 * $i),
2704
- // offset: 4 + 6 * $i; index to first sheet in EXTERNALBOOK record
2705
- 'firstSheetIndex' => self::_GetInt2d($recordData, 4 + 6 * $i),
2706
- // offset: 6 + 6 * $i; index to last sheet in EXTERNALBOOK record
2707
- 'lastSheetIndex' => self::_GetInt2d($recordData, 6 + 6 * $i),
2708
- );
2709
- }
2710
- }
2711
- }
2712
-
2713
-
2714
- /**
2715
- * DEFINEDNAME
2716
- *
2717
- * This record is part of a Link Table. It contains the name
2718
- * and the token array of an internal defined name. Token
2719
- * arrays of defined names contain tokens with aberrant
2720
- * token classes.
2721
- *
2722
- * -- "OpenOffice.org's Documentation of the Microsoft
2723
- * Excel File Format"
2724
- */
2725
- private function _readDefinedName()
2726
- {
2727
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2728
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2729
-
2730
- // move stream pointer to next record
2731
- $this->_pos += 4 + $length;
2732
-
2733
- if ($this->_version == self::XLS_BIFF8) {
2734
- // retrieves named cells
2735
-
2736
- // offset: 0; size: 2; option flags
2737
- $opts = self::_GetInt2d($recordData, 0);
2738
-
2739
- // bit: 5; mask: 0x0020; 0 = user-defined name, 1 = built-in-name
2740
- $isBuiltInName = (0x0020 & $opts) >> 5;
2741
-
2742
- // offset: 2; size: 1; keyboard shortcut
2743
-
2744
- // offset: 3; size: 1; length of the name (character count)
2745
- $nlen = ord($recordData{3});
2746
-
2747
- // offset: 4; size: 2; size of the formula data (it can happen that this is zero)
2748
- // note: there can also be additional data, this is not included in $flen
2749
- $flen = self::_GetInt2d($recordData, 4);
2750
-
2751
- // offset: 8; size: 2; 0=Global name, otherwise index to sheet (1-based)
2752
- $scope = self::_GetInt2d($recordData, 8);
2753
-
2754
- // offset: 14; size: var; Name (Unicode string without length field)
2755
- $string = self::_readUnicodeString(substr($recordData, 14), $nlen);
2756
-
2757
- // offset: var; size: $flen; formula data
2758
- $offset = 14 + $string['size'];
2759
- $formulaStructure = pack('v', $flen) . substr($recordData, $offset);
2760
-
2761
- try {
2762
- $formula = $this->_getFormulaFromStructure($formulaStructure);
2763
- } catch (PHPExcel_Exception $e) {
2764
- $formula = '';
2765
- }
2766
-
2767
- $this->_definedname[] = array(
2768
- 'isBuiltInName' => $isBuiltInName,
2769
- 'name' => $string['value'],
2770
- 'formula' => $formula,
2771
- 'scope' => $scope,
2772
- );
2773
- }
2774
- }
2775
-
2776
-
2777
- /**
2778
- * Read MSODRAWINGGROUP record
2779
- */
2780
- private function _readMsoDrawingGroup()
2781
- {
2782
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2783
-
2784
- // get spliced record data
2785
- $splicedRecordData = $this->_getSplicedRecordData();
2786
- $recordData = $splicedRecordData['recordData'];
2787
-
2788
- $this->_drawingGroupData .= $recordData;
2789
- }
2790
-
2791
-
2792
- /**
2793
- * SST - Shared String Table
2794
- *
2795
- * This record contains a list of all strings used anywhere
2796
- * in the workbook. Each string occurs only once. The
2797
- * workbook uses indexes into the list to reference the
2798
- * strings.
2799
- *
2800
- * -- "OpenOffice.org's Documentation of the Microsoft
2801
- * Excel File Format"
2802
- **/
2803
- private function _readSst()
2804
- {
2805
- // offset within (spliced) record data
2806
- $pos = 0;
2807
-
2808
- // get spliced record data
2809
- $splicedRecordData = $this->_getSplicedRecordData();
2810
-
2811
- $recordData = $splicedRecordData['recordData'];
2812
- $spliceOffsets = $splicedRecordData['spliceOffsets'];
2813
-
2814
- // offset: 0; size: 4; total number of strings in the workbook
2815
- $pos += 4;
2816
-
2817
- // offset: 4; size: 4; number of following strings ($nm)
2818
- $nm = self::_GetInt4d($recordData, 4);
2819
- $pos += 4;
2820
-
2821
- // loop through the Unicode strings (16-bit length)
2822
- for ($i = 0; $i < $nm; ++$i) {
2823
-
2824
- // number of characters in the Unicode string
2825
- $numChars = self::_GetInt2d($recordData, $pos);
2826
- $pos += 2;
2827
-
2828
- // option flags
2829
- $optionFlags = ord($recordData{$pos});
2830
- ++$pos;
2831
-
2832
- // bit: 0; mask: 0x01; 0 = compressed; 1 = uncompressed
2833
- $isCompressed = (($optionFlags & 0x01) == 0) ;
2834
-
2835
- // bit: 2; mask: 0x02; 0 = ordinary; 1 = Asian phonetic
2836
- $hasAsian = (($optionFlags & 0x04) != 0);
2837
-
2838
- // bit: 3; mask: 0x03; 0 = ordinary; 1 = Rich-Text
2839
- $hasRichText = (($optionFlags & 0x08) != 0);
2840
-
2841
- if ($hasRichText) {
2842
- // number of Rich-Text formatting runs
2843
- $formattingRuns = self::_GetInt2d($recordData, $pos);
2844
- $pos += 2;
2845
- }
2846
-
2847
- if ($hasAsian) {
2848
- // size of Asian phonetic setting
2849
- $extendedRunLength = self::_GetInt4d($recordData, $pos);
2850
- $pos += 4;
2851
- }
2852
-
2853
- // expected byte length of character array if not split
2854
- $len = ($isCompressed) ? $numChars : $numChars * 2;
2855
-
2856
- // look up limit position
2857
- foreach ($spliceOffsets as $spliceOffset) {
2858
- // it can happen that the string is empty, therefore we need
2859
- // <= and not just <
2860
- if ($pos <= $spliceOffset) {
2861
- $limitpos = $spliceOffset;
2862
- break;
2863
- }
2864
- }
2865
-
2866
- if ($pos + $len <= $limitpos) {
2867
- // character array is not split between records
2868
-
2869
- $retstr = substr($recordData, $pos, $len);
2870
- $pos += $len;
2871
-
2872
- } else {
2873
- // character array is split between records
2874
-
2875
- // first part of character array
2876
- $retstr = substr($recordData, $pos, $limitpos - $pos);
2877
-
2878
- $bytesRead = $limitpos - $pos;
2879
-
2880
- // remaining characters in Unicode string
2881
- $charsLeft = $numChars - (($isCompressed) ? $bytesRead : ($bytesRead / 2));
2882
-
2883
- $pos = $limitpos;
2884
-
2885
- // keep reading the characters
2886
- while ($charsLeft > 0) {
2887
-
2888
- // look up next limit position, in case the string span more than one continue record
2889
- foreach ($spliceOffsets as $spliceOffset) {
2890
- if ($pos < $spliceOffset) {
2891
- $limitpos = $spliceOffset;
2892
- break;
2893
- }
2894
- }
2895
-
2896
- // repeated option flags
2897
- // OpenOffice.org documentation 5.21
2898
- $option = ord($recordData{$pos});
2899
- ++$pos;
2900
-
2901
- if ($isCompressed && ($option == 0)) {
2902
- // 1st fragment compressed
2903
- // this fragment compressed
2904
- $len = min($charsLeft, $limitpos - $pos);
2905
- $retstr .= substr($recordData, $pos, $len);
2906
- $charsLeft -= $len;
2907
- $isCompressed = true;
2908
-
2909
- } elseif (!$isCompressed && ($option != 0)) {
2910
- // 1st fragment uncompressed
2911
- // this fragment uncompressed
2912
- $len = min($charsLeft * 2, $limitpos - $pos);
2913
- $retstr .= substr($recordData, $pos, $len);
2914
- $charsLeft -= $len / 2;
2915
- $isCompressed = false;
2916
-
2917
- } elseif (!$isCompressed && ($option == 0)) {
2918
- // 1st fragment uncompressed
2919
- // this fragment compressed
2920
- $len = min($charsLeft, $limitpos - $pos);
2921
- for ($j = 0; $j < $len; ++$j) {
2922
- $retstr .= $recordData{$pos + $j} . chr(0);
2923
- }
2924
- $charsLeft -= $len;
2925
- $isCompressed = false;
2926
-
2927
- } else {
2928
- // 1st fragment compressed
2929
- // this fragment uncompressed
2930
- $newstr = '';
2931
- for ($j = 0; $j < strlen($retstr); ++$j) {
2932
- $newstr .= $retstr[$j] . chr(0);
2933
- }
2934
- $retstr = $newstr;
2935
- $len = min($charsLeft * 2, $limitpos - $pos);
2936
- $retstr .= substr($recordData, $pos, $len);
2937
- $charsLeft -= $len / 2;
2938
- $isCompressed = false;
2939
- }
2940
-
2941
- $pos += $len;
2942
- }
2943
- }
2944
-
2945
- // convert to UTF-8
2946
- $retstr = self::_encodeUTF16($retstr, $isCompressed);
2947
-
2948
- // read additional Rich-Text information, if any
2949
- $fmtRuns = array();
2950
- if ($hasRichText) {
2951
- // list of formatting runs
2952
- for ($j = 0; $j < $formattingRuns; ++$j) {
2953
- // first formatted character; zero-based
2954
- $charPos = self::_GetInt2d($recordData, $pos + $j * 4);
2955
-
2956
- // index to font record
2957
- $fontIndex = self::_GetInt2d($recordData, $pos + 2 + $j * 4);
2958
-
2959
- $fmtRuns[] = array(
2960
- 'charPos' => $charPos,
2961
- 'fontIndex' => $fontIndex,
2962
- );
2963
- }
2964
- $pos += 4 * $formattingRuns;
2965
- }
2966
-
2967
- // read additional Asian phonetics information, if any
2968
- if ($hasAsian) {
2969
- // For Asian phonetic settings, we skip the extended string data
2970
- $pos += $extendedRunLength;
2971
- }
2972
-
2973
- // store the shared sting
2974
- $this->_sst[] = array(
2975
- 'value' => $retstr,
2976
- 'fmtRuns' => $fmtRuns,
2977
- );
2978
- }
2979
-
2980
- // _getSplicedRecordData() takes care of moving current position in data stream
2981
- }
2982
-
2983
-
2984
- /**
2985
- * Read PRINTGRIDLINES record
2986
- */
2987
- private function _readPrintGridlines()
2988
- {
2989
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2990
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2991
-
2992
- // move stream pointer to next record
2993
- $this->_pos += 4 + $length;
2994
-
2995
- if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
2996
- // offset: 0; size: 2; 0 = do not print sheet grid lines; 1 = print sheet gridlines
2997
- $printGridlines = (bool) self::_GetInt2d($recordData, 0);
2998
- $this->_phpSheet->setPrintGridlines($printGridlines);
2999
- }
3000
- }
3001
-
3002
-
3003
- /**
3004
- * Read DEFAULTROWHEIGHT record
3005
- */
3006
- private function _readDefaultRowHeight()
3007
- {
3008
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3009
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3010
-
3011
- // move stream pointer to next record
3012
- $this->_pos += 4 + $length;
3013
-
3014
- // offset: 0; size: 2; option flags
3015
- // offset: 2; size: 2; default height for unused rows, (twips 1/20 point)
3016
- $height = self::_GetInt2d($recordData, 2);
3017
- $this->_phpSheet->getDefaultRowDimension()->setRowHeight($height / 20);
3018
- }
3019
-
3020
-
3021
- /**
3022
- * Read SHEETPR record
3023
- */
3024
- private function _readSheetPr()
3025
- {
3026
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3027
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3028
-
3029
- // move stream pointer to next record
3030
- $this->_pos += 4 + $length;
3031
-
3032
- // offset: 0; size: 2
3033
-
3034
- // bit: 6; mask: 0x0040; 0 = outline buttons above outline group
3035
- $isSummaryBelow = (0x0040 & self::_GetInt2d($recordData, 0)) >> 6;
3036
- $this->_phpSheet->setShowSummaryBelow($isSummaryBelow);
3037
-
3038
- // bit: 7; mask: 0x0080; 0 = outline buttons left of outline group
3039
- $isSummaryRight = (0x0080 & self::_GetInt2d($recordData, 0)) >> 7;
3040
- $this->_phpSheet->setShowSummaryRight($isSummaryRight);
3041
-
3042
- // bit: 8; mask: 0x100; 0 = scale printout in percent, 1 = fit printout to number of pages
3043
- // this corresponds to radio button setting in page setup dialog in Excel
3044
- $this->_isFitToPages = (bool) ((0x0100 & self::_GetInt2d($recordData, 0)) >> 8);
3045
- }
3046
-
3047
-
3048
- /**
3049
- * Read HORIZONTALPAGEBREAKS record
3050
- */
3051
- private function _readHorizontalPageBreaks()
3052
- {
3053
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3054
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3055
-
3056
- // move stream pointer to next record
3057
- $this->_pos += 4 + $length;
3058
-
3059
- if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
3060
-
3061
- // offset: 0; size: 2; number of the following row index structures
3062
- $nm = self::_GetInt2d($recordData, 0);
3063
-
3064
- // offset: 2; size: 6 * $nm; list of $nm row index structures
3065
- for ($i = 0; $i < $nm; ++$i) {
3066
- $r = self::_GetInt2d($recordData, 2 + 6 * $i);
3067
- $cf = self::_GetInt2d($recordData, 2 + 6 * $i + 2);
3068
- $cl = self::_GetInt2d($recordData, 2 + 6 * $i + 4);
3069
-
3070
- // not sure why two column indexes are necessary?
3071
- $this->_phpSheet->setBreakByColumnAndRow($cf, $r, PHPExcel_Worksheet::BREAK_ROW);
3072
- }
3073
- }
3074
- }
3075
-
3076
-
3077
- /**
3078
- * Read VERTICALPAGEBREAKS record
3079
- */
3080
- private function _readVerticalPageBreaks()
3081
- {
3082
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3083
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3084
-
3085
- // move stream pointer to next record
3086
- $this->_pos += 4 + $length;
3087
-
3088
- if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
3089
- // offset: 0; size: 2; number of the following column index structures
3090
- $nm = self::_GetInt2d($recordData, 0);
3091
-
3092
- // offset: 2; size: 6 * $nm; list of $nm row index structures
3093
- for ($i = 0; $i < $nm; ++$i) {
3094
- $c = self::_GetInt2d($recordData, 2 + 6 * $i);
3095
- $rf = self::_GetInt2d($recordData, 2 + 6 * $i + 2);
3096
- $rl = self::_GetInt2d($recordData, 2 + 6 * $i + 4);
3097
-
3098
- // not sure why two row indexes are necessary?
3099
- $this->_phpSheet->setBreakByColumnAndRow($c, $rf, PHPExcel_Worksheet::BREAK_COLUMN);
3100
- }
3101
- }
3102
- }
3103
-
3104
-
3105
- /**
3106
- * Read HEADER record
3107
- */
3108
- private function _readHeader()
3109
- {
3110
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3111
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3112
-
3113
- // move stream pointer to next record
3114
- $this->_pos += 4 + $length;
3115
-
3116
- if (!$this->_readDataOnly) {
3117
- // offset: 0; size: var
3118
- // realized that $recordData can be empty even when record exists
3119
- if ($recordData) {
3120
- if ($this->_version == self::XLS_BIFF8) {
3121
- $string = self::_readUnicodeStringLong($recordData);
3122
- } else {
3123
- $string = $this->_readByteStringShort($recordData);
3124
- }
3125
-
3126
- $this->_phpSheet->getHeaderFooter()->setOddHeader($string['value']);
3127
- $this->_phpSheet->getHeaderFooter()->setEvenHeader($string['value']);
3128
- }
3129
- }
3130
- }
3131
-
3132
-
3133
- /**
3134
- * Read FOOTER record
3135
- */
3136
- private function _readFooter()
3137
- {
3138
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3139
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3140
-
3141
- // move stream pointer to next record
3142
- $this->_pos += 4 + $length;
3143
-
3144
- if (!$this->_readDataOnly) {
3145
- // offset: 0; size: var
3146
- // realized that $recordData can be empty even when record exists
3147
- if ($recordData) {
3148
- if ($this->_version == self::XLS_BIFF8) {
3149
- $string = self::_readUnicodeStringLong($recordData);
3150
- } else {
3151
- $string = $this->_readByteStringShort($recordData);
3152
- }
3153
- $this->_phpSheet->getHeaderFooter()->setOddFooter($string['value']);
3154
- $this->_phpSheet->getHeaderFooter()->setEvenFooter($string['value']);
3155
- }
3156
- }
3157
- }
3158
-
3159
-
3160
- /**
3161
- * Read HCENTER record
3162
- */
3163
- private function _readHcenter()
3164
- {
3165
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3166
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3167
-
3168
- // move stream pointer to next record
3169
- $this->_pos += 4 + $length;
3170
-
3171
- if (!$this->_readDataOnly) {
3172
- // offset: 0; size: 2; 0 = print sheet left aligned, 1 = print sheet centered horizontally
3173
- $isHorizontalCentered = (bool) self::_GetInt2d($recordData, 0);
3174
-
3175
- $this->_phpSheet->getPageSetup()->setHorizontalCentered($isHorizontalCentered);
3176
- }
3177
- }
3178
-
3179
-
3180
- /**
3181
- * Read VCENTER record
3182
- */
3183
- private function _readVcenter()
3184
- {
3185
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3186
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3187
-
3188
- // move stream pointer to next record
3189
- $this->_pos += 4 + $length;
3190
-
3191
- if (!$this->_readDataOnly) {
3192
- // offset: 0; size: 2; 0 = print sheet aligned at top page border, 1 = print sheet vertically centered
3193
- $isVerticalCentered = (bool) self::_GetInt2d($recordData, 0);
3194
-
3195
- $this->_phpSheet->getPageSetup()->setVerticalCentered($isVerticalCentered);
3196
- }
3197
- }
3198
-
3199
-
3200
- /**
3201
- * Read LEFTMARGIN record
3202
- */
3203
- private function _readLeftMargin()
3204
- {
3205
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3206
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3207
-
3208
- // move stream pointer to next record
3209
- $this->_pos += 4 + $length;
3210
-
3211
- if (!$this->_readDataOnly) {
3212
- // offset: 0; size: 8
3213
- $this->_phpSheet->getPageMargins()->setLeft(self::_extractNumber($recordData));
3214
- }
3215
- }
3216
-
3217
-
3218
- /**
3219
- * Read RIGHTMARGIN record
3220
- */
3221
- private function _readRightMargin()
3222
- {
3223
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3224
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3225
-
3226
- // move stream pointer to next record
3227
- $this->_pos += 4 + $length;
3228
-
3229
- if (!$this->_readDataOnly) {
3230
- // offset: 0; size: 8
3231
- $this->_phpSheet->getPageMargins()->setRight(self::_extractNumber($recordData));
3232
- }
3233
- }
3234
-
3235
-
3236
- /**
3237
- * Read TOPMARGIN record
3238
- */
3239
- private function _readTopMargin()
3240
- {
3241
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3242
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3243
-
3244
- // move stream pointer to next record
3245
- $this->_pos += 4 + $length;
3246
-
3247
- if (!$this->_readDataOnly) {
3248
- // offset: 0; size: 8
3249
- $this->_phpSheet->getPageMargins()->setTop(self::_extractNumber($recordData));
3250
- }
3251
- }
3252
-
3253
-
3254
- /**
3255
- * Read BOTTOMMARGIN record
3256
- */
3257
- private function _readBottomMargin()
3258
- {
3259
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3260
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3261
-
3262
- // move stream pointer to next record
3263
- $this->_pos += 4 + $length;
3264
-
3265
- if (!$this->_readDataOnly) {
3266
- // offset: 0; size: 8
3267
- $this->_phpSheet->getPageMargins()->setBottom(self::_extractNumber($recordData));
3268
- }
3269
- }
3270
-
3271
-
3272
- /**
3273
- * Read PAGESETUP record
3274
- */
3275
- private function _readPageSetup()
3276
- {
3277
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3278
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3279
-
3280
- // move stream pointer to next record
3281
- $this->_pos += 4 + $length;
3282
-
3283
- if (!$this->_readDataOnly) {
3284
- // offset: 0; size: 2; paper size
3285
- $paperSize = self::_GetInt2d($recordData, 0);
3286
-
3287
- // offset: 2; size: 2; scaling factor
3288
- $scale = self::_GetInt2d($recordData, 2);
3289
-
3290
- // offset: 6; size: 2; fit worksheet width to this number of pages, 0 = use as many as needed
3291
- $fitToWidth = self::_GetInt2d($recordData, 6);
3292
-
3293
- // offset: 8; size: 2; fit worksheet height to this number of pages, 0 = use as many as needed
3294
- $fitToHeight = self::_GetInt2d($recordData, 8);
3295
-
3296
- // offset: 10; size: 2; option flags
3297
-
3298
- // bit: 1; mask: 0x0002; 0=landscape, 1=portrait
3299
- $isPortrait = (0x0002 & self::_GetInt2d($recordData, 10)) >> 1;
3300
-
3301
- // bit: 2; mask: 0x0004; 1= paper size, scaling factor, paper orient. not init
3302
- // when this bit is set, do not use flags for those properties
3303
- $isNotInit = (0x0004 & self::_GetInt2d($recordData, 10)) >> 2;
3304
-
3305
- if (!$isNotInit) {
3306
- $this->_phpSheet->getPageSetup()->setPaperSize($paperSize);
3307
- switch ($isPortrait) {
3308
- case 0: $this->_phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE); break;
3309
- case 1: $this->_phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_PORTRAIT); break;
3310
- }
3311
-
3312
- $this->_phpSheet->getPageSetup()->setScale($scale, false);
3313
- $this->_phpSheet->getPageSetup()->setFitToPage((bool) $this->_isFitToPages);
3314
- $this->_phpSheet->getPageSetup()->setFitToWidth($fitToWidth, false);
3315
- $this->_phpSheet->getPageSetup()->setFitToHeight($fitToHeight, false);
3316
- }
3317
-
3318
- // offset: 16; size: 8; header margin (IEEE 754 floating-point value)
3319
- $marginHeader = self::_extractNumber(substr($recordData, 16, 8));
3320
- $this->_phpSheet->getPageMargins()->setHeader($marginHeader);
3321
-
3322
- // offset: 24; size: 8; footer margin (IEEE 754 floating-point value)
3323
- $marginFooter = self::_extractNumber(substr($recordData, 24, 8));
3324
- $this->_phpSheet->getPageMargins()->setFooter($marginFooter);
3325
- }
3326
- }
3327
-
3328
-
3329
- /**
3330
- * PROTECT - Sheet protection (BIFF2 through BIFF8)
3331
- * if this record is omitted, then it also means no sheet protection
3332
- */
3333
- private function _readProtect()
3334
- {
3335
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3336
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3337
-
3338
- // move stream pointer to next record
3339
- $this->_pos += 4 + $length;
3340
-
3341
- if ($this->_readDataOnly) {
3342
- return;
3343
- }
3344
-
3345
- // offset: 0; size: 2;
3346
-
3347
- // bit 0, mask 0x01; 1 = sheet is protected
3348
- $bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
3349
- $this->_phpSheet->getProtection()->setSheet((bool)$bool);
3350
- }
3351
-
3352
-
3353
- /**
3354
- * SCENPROTECT
3355
- */
3356
- private function _readScenProtect()
3357
- {
3358
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3359
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3360
-
3361
- // move stream pointer to next record
3362
- $this->_pos += 4 + $length;
3363
-
3364
- if ($this->_readDataOnly) {
3365
- return;
3366
- }
3367
-
3368
- // offset: 0; size: 2;
3369
-
3370
- // bit: 0, mask 0x01; 1 = scenarios are protected
3371
- $bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
3372
-
3373
- $this->_phpSheet->getProtection()->setScenarios((bool)$bool);
3374
- }
3375
-
3376
-
3377
- /**
3378
- * OBJECTPROTECT
3379
- */
3380
- private function _readObjectProtect()
3381
- {
3382
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3383
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3384
-
3385
- // move stream pointer to next record
3386
- $this->_pos += 4 + $length;
3387
-
3388
- if ($this->_readDataOnly) {
3389
- return;
3390
- }
3391
-
3392
- // offset: 0; size: 2;
3393
-
3394
- // bit: 0, mask 0x01; 1 = objects are protected
3395
- $bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
3396
-
3397
- $this->_phpSheet->getProtection()->setObjects((bool)$bool);
3398
- }
3399
-
3400
-
3401
- /**
3402
- * PASSWORD - Sheet protection (hashed) password (BIFF2 through BIFF8)
3403
- */
3404
- private function _readPassword()
3405
- {
3406
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3407
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3408
-
3409
- // move stream pointer to next record
3410
- $this->_pos += 4 + $length;
3411
-
3412
- if (!$this->_readDataOnly) {
3413
- // offset: 0; size: 2; 16-bit hash value of password
3414
- $password = strtoupper(dechex(self::_GetInt2d($recordData, 0))); // the hashed password
3415
- $this->_phpSheet->getProtection()->setPassword($password, true);
3416
- }
3417
- }
3418
-
3419
-
3420
- /**
3421
- * Read DEFCOLWIDTH record
3422
- */
3423
- private function _readDefColWidth()
3424
- {
3425
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3426
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3427
-
3428
- // move stream pointer to next record
3429
- $this->_pos += 4 + $length;
3430
-
3431
- // offset: 0; size: 2; default column width
3432
- $width = self::_GetInt2d($recordData, 0);
3433
- if ($width != 8) {
3434
- $this->_phpSheet->getDefaultColumnDimension()->setWidth($width);
3435
- }
3436
- }
3437
-
3438
-
3439
- /**
3440
- * Read COLINFO record
3441
- */
3442
- private function _readColInfo()
3443
- {
3444
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3445
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3446
-
3447
- // move stream pointer to next record
3448
- $this->_pos += 4 + $length;
3449
-
3450
- if (!$this->_readDataOnly) {
3451
- // offset: 0; size: 2; index to first column in range
3452
- $fc = self::_GetInt2d($recordData, 0); // first column index
3453
-
3454
- // offset: 2; size: 2; index to last column in range
3455
- $lc = self::_GetInt2d($recordData, 2); // first column index
3456
-
3457
- // offset: 4; size: 2; width of the column in 1/256 of the width of the zero character
3458
- $width = self::_GetInt2d($recordData, 4);
3459
-
3460
- // offset: 6; size: 2; index to XF record for default column formatting
3461
- $xfIndex = self::_GetInt2d($recordData, 6);
3462
-
3463
- // offset: 8; size: 2; option flags
3464
-
3465
- // bit: 0; mask: 0x0001; 1= columns are hidden
3466
- $isHidden = (0x0001 & self::_GetInt2d($recordData, 8)) >> 0;
3467
-
3468
- // bit: 10-8; mask: 0x0700; outline level of the columns (0 = no outline)
3469
- $level = (0x0700 & self::_GetInt2d($recordData, 8)) >> 8;
3470
-
3471
- // bit: 12; mask: 0x1000; 1 = collapsed
3472
- $isCollapsed = (0x1000 & self::_GetInt2d($recordData, 8)) >> 12;
3473
-
3474
- // offset: 10; size: 2; not used
3475
-
3476
- for ($i = $fc; $i <= $lc; ++$i) {
3477
- if ($lc == 255 || $lc == 256) {
3478
- $this->_phpSheet->getDefaultColumnDimension()->setWidth($width / 256);
3479
- break;
3480
- }
3481
- $this->_phpSheet->getColumnDimensionByColumn($i)->setWidth($width / 256);
3482
- $this->_phpSheet->getColumnDimensionByColumn($i)->setVisible(!$isHidden);
3483
- $this->_phpSheet->getColumnDimensionByColumn($i)->setOutlineLevel($level);
3484
- $this->_phpSheet->getColumnDimensionByColumn($i)->setCollapsed($isCollapsed);
3485
- $this->_phpSheet->getColumnDimensionByColumn($i)->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3486
- }
3487
- }
3488
- }
3489
-
3490
-
3491
- /**
3492
- * ROW
3493
- *
3494
- * This record contains the properties of a single row in a
3495
- * sheet. Rows and cells in a sheet are divided into blocks
3496
- * of 32 rows.
3497
- *
3498
- * -- "OpenOffice.org's Documentation of the Microsoft
3499
- * Excel File Format"
3500
- */
3501
- private function _readRow()
3502
- {
3503
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3504
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3505
-
3506
- // move stream pointer to next record
3507
- $this->_pos += 4 + $length;
3508
-
3509
- if (!$this->_readDataOnly) {
3510
- // offset: 0; size: 2; index of this row
3511
- $r = self::_GetInt2d($recordData, 0);
3512
-
3513
- // offset: 2; size: 2; index to column of the first cell which is described by a cell record
3514
-
3515
- // offset: 4; size: 2; index to column of the last cell which is described by a cell record, increased by 1
3516
-
3517
- // offset: 6; size: 2;
3518
-
3519
- // bit: 14-0; mask: 0x7FFF; height of the row, in twips = 1/20 of a point
3520
- $height = (0x7FFF & self::_GetInt2d($recordData, 6)) >> 0;
3521
-
3522
- // bit: 15: mask: 0x8000; 0 = row has custom height; 1= row has default height
3523
- $useDefaultHeight = (0x8000 & self::_GetInt2d($recordData, 6)) >> 15;
3524
-
3525
- if (!$useDefaultHeight) {
3526
- $this->_phpSheet->getRowDimension($r + 1)->setRowHeight($height / 20);
3527
- }
3528
-
3529
- // offset: 8; size: 2; not used
3530
-
3531
- // offset: 10; size: 2; not used in BIFF5-BIFF8
3532
-
3533
- // offset: 12; size: 4; option flags and default row formatting
3534
-
3535
- // bit: 2-0: mask: 0x00000007; outline level of the row
3536
- $level = (0x00000007 & self::_GetInt4d($recordData, 12)) >> 0;
3537
- $this->_phpSheet->getRowDimension($r + 1)->setOutlineLevel($level);
3538
-
3539
- // bit: 4; mask: 0x00000010; 1 = outline group start or ends here... and is collapsed
3540
- $isCollapsed = (0x00000010 & self::_GetInt4d($recordData, 12)) >> 4;
3541
- $this->_phpSheet->getRowDimension($r + 1)->setCollapsed($isCollapsed);
3542
-
3543
- // bit: 5; mask: 0x00000020; 1 = row is hidden
3544
- $isHidden = (0x00000020 & self::_GetInt4d($recordData, 12)) >> 5;
3545
- $this->_phpSheet->getRowDimension($r + 1)->setVisible(!$isHidden);
3546
-
3547
- // bit: 7; mask: 0x00000080; 1 = row has explicit format
3548
- $hasExplicitFormat = (0x00000080 & self::_GetInt4d($recordData, 12)) >> 7;
3549
-
3550
- // bit: 27-16; mask: 0x0FFF0000; only applies when hasExplicitFormat = 1; index to XF record
3551
- $xfIndex = (0x0FFF0000 & self::_GetInt4d($recordData, 12)) >> 16;
3552
-
3553
- if ($hasExplicitFormat) {
3554
- $this->_phpSheet->getRowDimension($r + 1)->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3555
- }
3556
- }
3557
- }
3558
-
3559
-
3560
- /**
3561
- * Read RK record
3562
- * This record represents a cell that contains an RK value
3563
- * (encoded integer or floating-point value). If a
3564
- * floating-point value cannot be encoded to an RK value,
3565
- * a NUMBER record will be written. This record replaces the
3566
- * record INTEGER written in BIFF2.
3567
- *
3568
- * -- "OpenOffice.org's Documentation of the Microsoft
3569
- * Excel File Format"
3570
- */
3571
- private function _readRk()
3572
- {
3573
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3574
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3575
-
3576
- // move stream pointer to next record
3577
- $this->_pos += 4 + $length;
3578
-
3579
- // offset: 0; size: 2; index to row
3580
- $row = self::_GetInt2d($recordData, 0);
3581
-
3582
- // offset: 2; size: 2; index to column
3583
- $column = self::_GetInt2d($recordData, 2);
3584
- $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3585
-
3586
- // Read cell?
3587
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3588
- // offset: 4; size: 2; index to XF record
3589
- $xfIndex = self::_GetInt2d($recordData, 4);
3590
-
3591
- // offset: 6; size: 4; RK value
3592
- $rknum = self::_GetInt4d($recordData, 6);
3593
- $numValue = self::_GetIEEE754($rknum);
3594
-
3595
- $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3596
- if (!$this->_readDataOnly) {
3597
- // add style information
3598
- $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3599
- }
3600
-
3601
- // add cell
3602
- $cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
3603
- }
3604
- }
3605
-
3606
-
3607
- /**
3608
- * Read LABELSST record
3609
- * This record represents a cell that contains a string. It
3610
- * replaces the LABEL record and RSTRING record used in
3611
- * BIFF2-BIFF5.
3612
- *
3613
- * -- "OpenOffice.org's Documentation of the Microsoft
3614
- * Excel File Format"
3615
- */
3616
- private function _readLabelSst()
3617
- {
3618
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3619
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3620
-
3621
- // move stream pointer to next record
3622
- $this->_pos += 4 + $length;
3623
-
3624
- // offset: 0; size: 2; index to row
3625
- $row = self::_GetInt2d($recordData, 0);
3626
-
3627
- // offset: 2; size: 2; index to column
3628
- $column = self::_GetInt2d($recordData, 2);
3629
- $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3630
-
3631
- // Read cell?
3632
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3633
- // offset: 4; size: 2; index to XF record
3634
- $xfIndex = self::_GetInt2d($recordData, 4);
3635
-
3636
- // offset: 6; size: 4; index to SST record
3637
- $index = self::_GetInt4d($recordData, 6);
3638
-
3639
- // add cell
3640
- if (($fmtRuns = $this->_sst[$index]['fmtRuns']) && !$this->_readDataOnly) {
3641
- // then we should treat as rich text
3642
- $richText = new PHPExcel_RichText();
3643
- $charPos = 0;
3644
- $sstCount = count($this->_sst[$index]['fmtRuns']);
3645
- for ($i = 0; $i <= $sstCount; ++$i) {
3646
- if (isset($fmtRuns[$i])) {
3647
- $text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, $fmtRuns[$i]['charPos'] - $charPos);
3648
- $charPos = $fmtRuns[$i]['charPos'];
3649
- } else {
3650
- $text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, PHPExcel_Shared_String::CountCharacters($this->_sst[$index]['value']));
3651
- }
3652
-
3653
- if (PHPExcel_Shared_String::CountCharacters($text) > 0) {
3654
- if ($i == 0) { // first text run, no style
3655
- $richText->createText($text);
3656
- } else {
3657
- $textRun = $richText->createTextRun($text);
3658
- if (isset($fmtRuns[$i - 1])) {
3659
- if ($fmtRuns[$i - 1]['fontIndex'] < 4) {
3660
- $fontIndex = $fmtRuns[$i - 1]['fontIndex'];
3661
- } else {
3662
- // this has to do with that index 4 is omitted in all BIFF versions for some strange reason
3663
- // check the OpenOffice documentation of the FONT record
3664
- $fontIndex = $fmtRuns[$i - 1]['fontIndex'] - 1;
3665
- }
3666
- $textRun->setFont(clone $this->_objFonts[$fontIndex]);
3667
- }
3668
- }
3669
- }
3670
- }
3671
- $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3672
- $cell->setValueExplicit($richText, PHPExcel_Cell_DataType::TYPE_STRING);
3673
- } else {
3674
- $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3675
- $cell->setValueExplicit($this->_sst[$index]['value'], PHPExcel_Cell_DataType::TYPE_STRING);
3676
- }
3677
-
3678
- if (!$this->_readDataOnly) {
3679
- // add style information
3680
- $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3681
- }
3682
- }
3683
- }
3684
-
3685
-
3686
- /**
3687
- * Read MULRK record
3688
- * This record represents a cell range containing RK value
3689
- * cells. All cells are located in the same row.
3690
- *
3691
- * -- "OpenOffice.org's Documentation of the Microsoft
3692
- * Excel File Format"
3693
- */
3694
- private function _readMulRk()
3695
- {
3696
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3697
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3698
-
3699
- // move stream pointer to next record
3700
- $this->_pos += 4 + $length;
3701
-
3702
- // offset: 0; size: 2; index to row
3703
- $row = self::_GetInt2d($recordData, 0);
3704
-
3705
- // offset: 2; size: 2; index to first column
3706
- $colFirst = self::_GetInt2d($recordData, 2);
3707
-
3708
- // offset: var; size: 2; index to last column
3709
- $colLast = self::_GetInt2d($recordData, $length - 2);
3710
- $columns = $colLast - $colFirst + 1;
3711
-
3712
- // offset within record data
3713
- $offset = 4;
3714
-
3715
- for ($i = 0; $i < $columns; ++$i) {
3716
- $columnString = PHPExcel_Cell::stringFromColumnIndex($colFirst + $i);
3717
-
3718
- // Read cell?
3719
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3720
-
3721
- // offset: var; size: 2; index to XF record
3722
- $xfIndex = self::_GetInt2d($recordData, $offset);
3723
-
3724
- // offset: var; size: 4; RK value
3725
- $numValue = self::_GetIEEE754(self::_GetInt4d($recordData, $offset + 2));
3726
- $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3727
- if (!$this->_readDataOnly) {
3728
- // add style
3729
- $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3730
- }
3731
-
3732
- // add cell value
3733
- $cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
3734
- }
3735
-
3736
- $offset += 6;
3737
- }
3738
- }
3739
-
3740
-
3741
- /**
3742
- * Read NUMBER record
3743
- * This record represents a cell that contains a
3744
- * floating-point value.
3745
- *
3746
- * -- "OpenOffice.org's Documentation of the Microsoft
3747
- * Excel File Format"
3748
- */
3749
- private function _readNumber()
3750
- {
3751
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3752
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3753
-
3754
- // move stream pointer to next record
3755
- $this->_pos += 4 + $length;
3756
-
3757
- // offset: 0; size: 2; index to row
3758
- $row = self::_GetInt2d($recordData, 0);
3759
-
3760
- // offset: 2; size 2; index to column
3761
- $column = self::_GetInt2d($recordData, 2);
3762
- $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3763
-
3764
- // Read cell?
3765
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3766
- // offset 4; size: 2; index to XF record
3767
- $xfIndex = self::_GetInt2d($recordData, 4);
3768
-
3769
- $numValue = self::_extractNumber(substr($recordData, 6, 8));
3770
-
3771
- $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3772
- if (!$this->_readDataOnly) {
3773
- // add cell style
3774
- $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3775
- }
3776
-
3777
- // add cell value
3778
- $cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
3779
- }
3780
- }
3781
-
3782
-
3783
- /**
3784
- * Read FORMULA record + perhaps a following STRING record if formula result is a string
3785
- * This record contains the token array and the result of a
3786
- * formula cell.
3787
- *
3788
- * -- "OpenOffice.org's Documentation of the Microsoft
3789
- * Excel File Format"
3790
- */
3791
- private function _readFormula()
3792
- {
3793
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3794
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3795
-
3796
- // move stream pointer to next record
3797
- $this->_pos += 4 + $length;
3798
-
3799
- // offset: 0; size: 2; row index
3800
- $row = self::_GetInt2d($recordData, 0);
3801
-
3802
- // offset: 2; size: 2; col index
3803
- $column = self::_GetInt2d($recordData, 2);
3804
- $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3805
-
3806
- // offset: 20: size: variable; formula structure
3807
- $formulaStructure = substr($recordData, 20);
3808
-
3809
- // offset: 14: size: 2; option flags, recalculate always, recalculate on open etc.
3810
- $options = self::_GetInt2d($recordData, 14);
3811
-
3812
- // bit: 0; mask: 0x0001; 1 = recalculate always
3813
- // bit: 1; mask: 0x0002; 1 = calculate on open
3814
- // bit: 2; mask: 0x0008; 1 = part of a shared formula
3815
- $isPartOfSharedFormula = (bool) (0x0008 & $options);
3816
-
3817
- // WARNING:
3818
- // We can apparently not rely on $isPartOfSharedFormula. Even when $isPartOfSharedFormula = true
3819
- // the formula data may be ordinary formula data, therefore we need to check
3820
- // explicitly for the tExp token (0x01)
3821
- $isPartOfSharedFormula = $isPartOfSharedFormula && ord($formulaStructure{2}) == 0x01;
3822
-
3823
- if ($isPartOfSharedFormula) {
3824
- // part of shared formula which means there will be a formula with a tExp token and nothing else
3825
- // get the base cell, grab tExp token
3826
- $baseRow = self::_GetInt2d($formulaStructure, 3);
3827
- $baseCol = self::_GetInt2d($formulaStructure, 5);
3828
- $this->_baseCell = PHPExcel_Cell::stringFromColumnIndex($baseCol). ($baseRow + 1);
3829
- }
3830
-
3831
- // Read cell?
3832
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3833
-
3834
- if ($isPartOfSharedFormula) {
3835
- // formula is added to this cell after the sheet has been read
3836
- $this->_sharedFormulaParts[$columnString . ($row + 1)] = $this->_baseCell;
3837
- }
3838
-
3839
- // offset: 16: size: 4; not used
3840
-
3841
- // offset: 4; size: 2; XF index
3842
- $xfIndex = self::_GetInt2d($recordData, 4);
3843
-
3844
- // offset: 6; size: 8; result of the formula
3845
- if ( (ord($recordData{6}) == 0)
3846
- && (ord($recordData{12}) == 255)
3847
- && (ord($recordData{13}) == 255) ) {
3848
-
3849
- // String formula. Result follows in appended STRING record
3850
- $dataType = PHPExcel_Cell_DataType::TYPE_STRING;
3851
-
3852
- // read possible SHAREDFMLA record
3853
- $code = self::_GetInt2d($this->_data, $this->_pos);
3854
- if ($code == self::XLS_Type_SHAREDFMLA) {
3855
- $this->_readSharedFmla();
3856
- }
3857
-
3858
- // read STRING record
3859
- $value = $this->_readString();
3860
-
3861
- } elseif ((ord($recordData{6}) == 1)
3862
- && (ord($recordData{12}) == 255)
3863
- && (ord($recordData{13}) == 255)) {
3864
-
3865
- // Boolean formula. Result is in +2; 0=false, 1=true
3866
- $dataType = PHPExcel_Cell_DataType::TYPE_BOOL;
3867
- $value = (bool) ord($recordData{8});
3868
-
3869
- } elseif ((ord($recordData{6}) == 2)
3870
- && (ord($recordData{12}) == 255)
3871
- && (ord($recordData{13}) == 255)) {
3872
-
3873
- // Error formula. Error code is in +2
3874
- $dataType = PHPExcel_Cell_DataType::TYPE_ERROR;
3875
- $value = self::_mapErrorCode(ord($recordData{8}));
3876
-
3877
- } elseif ((ord($recordData{6}) == 3)
3878
- && (ord($recordData{12}) == 255)
3879
- && (ord($recordData{13}) == 255)) {
3880
-
3881
- // Formula result is a null string
3882
- $dataType = PHPExcel_Cell_DataType::TYPE_NULL;
3883
- $value = '';
3884
-
3885
- } else {
3886
-
3887
- // forumla result is a number, first 14 bytes like _NUMBER record
3888
- $dataType = PHPExcel_Cell_DataType::TYPE_NUMERIC;
3889
- $value = self::_extractNumber(substr($recordData, 6, 8));
3890
-
3891
- }
3892
-
3893
- $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3894
- if (!$this->_readDataOnly) {
3895
- // add cell style
3896
- $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3897
- }
3898
-
3899
- // store the formula
3900
- if (!$isPartOfSharedFormula) {
3901
- // not part of shared formula
3902
- // add cell value. If we can read formula, populate with formula, otherwise just used cached value
3903
- try {
3904
- if ($this->_version != self::XLS_BIFF8) {
3905
- throw new PHPExcel_Reader_Exception('Not BIFF8. Can only read BIFF8 formulas');
3906
- }
3907
- $formula = $this->_getFormulaFromStructure($formulaStructure); // get formula in human language
3908
- $cell->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
3909
-
3910
- } catch (PHPExcel_Exception $e) {
3911
- $cell->setValueExplicit($value, $dataType);
3912
- }
3913
- } else {
3914
- if ($this->_version == self::XLS_BIFF8) {
3915
- // do nothing at this point, formula id added later in the code
3916
- } else {
3917
- $cell->setValueExplicit($value, $dataType);
3918
- }
3919
- }
3920
-
3921
- // store the cached calculated value
3922
- $cell->setCalculatedValue($value);
3923
- }
3924
- }
3925
-
3926
-
3927
- /**
3928
- * Read a SHAREDFMLA record. This function just stores the binary shared formula in the reader,
3929
- * which usually contains relative references.
3930
- * These will be used to construct the formula in each shared formula part after the sheet is read.
3931
- */
3932
- private function _readSharedFmla()
3933
- {
3934
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3935
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3936
-
3937
- // move stream pointer to next record
3938
- $this->_pos += 4 + $length;
3939
-
3940
- // offset: 0, size: 6; cell range address of the area used by the shared formula, not used for anything
3941
- $cellRange = substr($recordData, 0, 6);
3942
- $cellRange = $this->_readBIFF5CellRangeAddressFixed($cellRange); // note: even BIFF8 uses BIFF5 syntax
3943
-
3944
- // offset: 6, size: 1; not used
3945
-
3946
- // offset: 7, size: 1; number of existing FORMULA records for this shared formula
3947
- $no = ord($recordData{7});
3948
-
3949
- // offset: 8, size: var; Binary token array of the shared formula
3950
- $formula = substr($recordData, 8);
3951
-
3952
- // at this point we only store the shared formula for later use
3953
- $this->_sharedFormulas[$this->_baseCell] = $formula;
3954
-
3955
- }
3956
-
3957
-
3958
- /**
3959
- * Read a STRING record from current stream position and advance the stream pointer to next record
3960
- * This record is used for storing result from FORMULA record when it is a string, and
3961
- * it occurs directly after the FORMULA record
3962
- *
3963
- * @return string The string contents as UTF-8
3964
- */
3965
- private function _readString()
3966
- {
3967
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3968
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3969
-
3970
- // move stream pointer to next record
3971
- $this->_pos += 4 + $length;
3972
-
3973
- if ($this->_version == self::XLS_BIFF8) {
3974
- $string = self::_readUnicodeStringLong($recordData);
3975
- $value = $string['value'];
3976
- } else {
3977
- $string = $this->_readByteStringLong($recordData);
3978
- $value = $string['value'];
3979
- }
3980
-
3981
- return $value;
3982
- }
3983
-
3984
-
3985
- /**
3986
- * Read BOOLERR record
3987
- * This record represents a Boolean value or error value
3988
- * cell.
3989
- *
3990
- * -- "OpenOffice.org's Documentation of the Microsoft
3991
- * Excel File Format"
3992
- */
3993
- private function _readBoolErr()
3994
- {
3995
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3996
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3997
-
3998
- // move stream pointer to next record
3999
- $this->_pos += 4 + $length;
4000
-
4001
- // offset: 0; size: 2; row index
4002
- $row = self::_GetInt2d($recordData, 0);
4003
-
4004
- // offset: 2; size: 2; column index
4005
- $column = self::_GetInt2d($recordData, 2);
4006
- $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
4007
-
4008
- // Read cell?
4009
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
4010
- // offset: 4; size: 2; index to XF record
4011
- $xfIndex = self::_GetInt2d($recordData, 4);
4012
-
4013
- // offset: 6; size: 1; the boolean value or error value
4014
- $boolErr = ord($recordData{6});
4015
-
4016
- // offset: 7; size: 1; 0=boolean; 1=error
4017
- $isError = ord($recordData{7});
4018
-
4019
- $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
4020
- switch ($isError) {
4021
- case 0: // boolean
4022
- $value = (bool) $boolErr;
4023
-
4024
- // add cell value
4025
- $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_BOOL);
4026
- break;
4027
-
4028
- case 1: // error type
4029
- $value = self::_mapErrorCode($boolErr);
4030
-
4031
- // add cell value
4032
- $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_ERROR);
4033
- break;
4034
- }
4035
-
4036
- if (!$this->_readDataOnly) {
4037
- // add cell style
4038
- $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
4039
- }
4040
- }
4041
- }
4042
-
4043
-
4044
- /**
4045
- * Read MULBLANK record
4046
- * This record represents a cell range of empty cells. All
4047
- * cells are located in the same row
4048
- *
4049
- * -- "OpenOffice.org's Documentation of the Microsoft
4050
- * Excel File Format"
4051
- */
4052
- private function _readMulBlank()
4053
- {
4054
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4055
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4056
-
4057
- // move stream pointer to next record
4058
- $this->_pos += 4 + $length;
4059
-
4060
- // offset: 0; size: 2; index to row
4061
- $row = self::_GetInt2d($recordData, 0);
4062
-
4063
- // offset: 2; size: 2; index to first column
4064
- $fc = self::_GetInt2d($recordData, 2);
4065
-
4066
- // offset: 4; size: 2 x nc; list of indexes to XF records
4067
- // add style information
4068
- if (!$this->_readDataOnly) {
4069
- for ($i = 0; $i < $length / 2 - 3; ++$i) {
4070
- $columnString = PHPExcel_Cell::stringFromColumnIndex($fc + $i);
4071
-
4072
- // Read cell?
4073
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
4074
- $xfIndex = self::_GetInt2d($recordData, 4 + 2 * $i);
4075
- $this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
4076
- }
4077
- }
4078
- }
4079
-
4080
- // offset: 6; size 2; index to last column (not needed)
4081
- }
4082
-
4083
-
4084
- /**
4085
- * Read LABEL record
4086
- * This record represents a cell that contains a string. In
4087
- * BIFF8 it is usually replaced by the LABELSST record.
4088
- * Excel still uses this record, if it copies unformatted
4089
- * text cells to the clipboard.
4090
- *
4091
- * -- "OpenOffice.org's Documentation of the Microsoft
4092
- * Excel File Format"
4093
- */
4094
- private function _readLabel()
4095
- {
4096
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4097
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4098
-
4099
- // move stream pointer to next record
4100
- $this->_pos += 4 + $length;
4101
-
4102
- // offset: 0; size: 2; index to row
4103
- $row = self::_GetInt2d($recordData, 0);
4104
-
4105
- // offset: 2; size: 2; index to column
4106
- $column = self::_GetInt2d($recordData, 2);
4107
- $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
4108
-
4109
- // Read cell?
4110
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
4111
- // offset: 4; size: 2; XF index
4112
- $xfIndex = self::_GetInt2d($recordData, 4);
4113
-
4114
- // add cell value
4115
- // todo: what if string is very long? continue record
4116
- if ($this->_version == self::XLS_BIFF8) {
4117
- $string = self::_readUnicodeStringLong(substr($recordData, 6));
4118
- $value = $string['value'];
4119
- } else {
4120
- $string = $this->_readByteStringLong(substr($recordData, 6));
4121
- $value = $string['value'];
4122
- }
4123
- $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
4124
- $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
4125
-
4126
- if (!$this->_readDataOnly) {
4127
- // add cell style
4128
- $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
4129
- }
4130
- }
4131
- }
4132
-
4133
-
4134
- /**
4135
- * Read BLANK record
4136
- */
4137
- private function _readBlank()
4138
- {
4139
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4140
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4141
-
4142
- // move stream pointer to next record
4143
- $this->_pos += 4 + $length;
4144
-
4145
- // offset: 0; size: 2; row index
4146
- $row = self::_GetInt2d($recordData, 0);
4147
-
4148
- // offset: 2; size: 2; col index
4149
- $col = self::_GetInt2d($recordData, 2);
4150
- $columnString = PHPExcel_Cell::stringFromColumnIndex($col);
4151
-
4152
- // Read cell?
4153
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
4154
- // offset: 4; size: 2; XF index
4155
- $xfIndex = self::_GetInt2d($recordData, 4);
4156
-
4157
- // add style information
4158
- if (!$this->_readDataOnly) {
4159
- $this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
4160
- }
4161
- }
4162
-
4163
- }
4164
-
4165
-
4166
- /**
4167
- * Read MSODRAWING record
4168
- */
4169
- private function _readMsoDrawing()
4170
- {
4171
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4172
-
4173
- // get spliced record data
4174
- $splicedRecordData = $this->_getSplicedRecordData();
4175
- $recordData = $splicedRecordData['recordData'];
4176
-
4177
- $this->_drawingData .= $recordData;
4178
- }
4179
-
4180
-
4181
- /**
4182
- * Read OBJ record
4183
- */
4184
- private function _readObj()
4185
- {
4186
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4187
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4188
-
4189
- // move stream pointer to next record
4190
- $this->_pos += 4 + $length;
4191
-
4192
- if ($this->_readDataOnly || $this->_version != self::XLS_BIFF8) {
4193
- return;
4194
- }
4195
-
4196
- // recordData consists of an array of subrecords looking like this:
4197
- // ft: 2 bytes; ftCmo type (0x15)
4198
- // cb: 2 bytes; size in bytes of ftCmo data
4199
- // ot: 2 bytes; Object Type
4200
- // id: 2 bytes; Object id number
4201
- // grbit: 2 bytes; Option Flags
4202
- // data: var; subrecord data
4203
-
4204
- // for now, we are just interested in the second subrecord containing the object type
4205
- $ftCmoType = self::_GetInt2d($recordData, 0);
4206
- $cbCmoSize = self::_GetInt2d($recordData, 2);
4207
- $otObjType = self::_GetInt2d($recordData, 4);
4208
- $idObjID = self::_GetInt2d($recordData, 6);
4209
- $grbitOpts = self::_GetInt2d($recordData, 6);
4210
-
4211
- $this->_objs[] = array(
4212
- 'ftCmoType' => $ftCmoType,
4213
- 'cbCmoSize' => $cbCmoSize,
4214
- 'otObjType' => $otObjType,
4215
- 'idObjID' => $idObjID,
4216
- 'grbitOpts' => $grbitOpts
4217
- );
4218
- $this->textObjRef = $idObjID;
4219
-
4220
- // echo '<b>_readObj()</b><br />';
4221
- // var_dump(end($this->_objs));
4222
- // echo '<br />';
4223
- }
4224
-
4225
-
4226
- /**
4227
- * Read WINDOW2 record
4228
- */
4229
- private function _readWindow2()
4230
- {
4231
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4232
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4233
-
4234
- // move stream pointer to next record
4235
- $this->_pos += 4 + $length;
4236
-
4237
- // offset: 0; size: 2; option flags
4238
- $options = self::_GetInt2d($recordData, 0);
4239
-
4240
- // offset: 2; size: 2; index to first visible row
4241
- $firstVisibleRow = self::_GetInt2d($recordData, 2);
4242
-
4243
- // offset: 4; size: 2; index to first visible colum
4244
- $firstVisibleColumn = self::_GetInt2d($recordData, 4);
4245
- if ($this->_version === self::XLS_BIFF8) {
4246
- // offset: 8; size: 2; not used
4247
- // offset: 10; size: 2; cached magnification factor in page break preview (in percent); 0 = Default (60%)
4248
- // offset: 12; size: 2; cached magnification factor in normal view (in percent); 0 = Default (100%)
4249
- // offset: 14; size: 4; not used
4250
- $zoomscaleInPageBreakPreview = self::_GetInt2d($recordData, 10);
4251
- if ($zoomscaleInPageBreakPreview === 0) $zoomscaleInPageBreakPreview = 60;
4252
- $zoomscaleInNormalView = self::_GetInt2d($recordData, 12);
4253
- if ($zoomscaleInNormalView === 0) $zoomscaleInNormalView = 100;
4254
- }
4255
-
4256
- // bit: 1; mask: 0x0002; 0 = do not show gridlines, 1 = show gridlines
4257
- $showGridlines = (bool) ((0x0002 & $options) >> 1);
4258
- $this->_phpSheet->setShowGridlines($showGridlines);
4259
-
4260
- // bit: 2; mask: 0x0004; 0 = do not show headers, 1 = show headers
4261
- $showRowColHeaders = (bool) ((0x0004 & $options) >> 2);
4262
- $this->_phpSheet->setShowRowColHeaders($showRowColHeaders);
4263
-
4264
- // bit: 3; mask: 0x0008; 0 = panes are not frozen, 1 = panes are frozen
4265
- $this->_frozen = (bool) ((0x0008 & $options) >> 3);
4266
-
4267
- // bit: 6; mask: 0x0040; 0 = columns from left to right, 1 = columns from right to left
4268
- $this->_phpSheet->setRightToLeft((bool)((0x0040 & $options) >> 6));
4269
-
4270
- // bit: 10; mask: 0x0400; 0 = sheet not active, 1 = sheet active
4271
- $isActive = (bool) ((0x0400 & $options) >> 10);
4272
- if ($isActive) {
4273
- $this->_phpExcel->setActiveSheetIndex($this->_phpExcel->getIndex($this->_phpSheet));
4274
- }
4275
-
4276
- // bit: 11; mask: 0x0800; 0 = normal view, 1 = page break view
4277
- $isPageBreakPreview = (bool) ((0x0800 & $options) >> 11);
4278
-
4279
- //FIXME: set $firstVisibleRow and $firstVisibleColumn
4280
-
4281
- if ($this->_phpSheet->getSheetView()->getView() !== PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_LAYOUT) {
4282
- //NOTE: this setting is inferior to page layout view(Excel2007-)
4283
- $view = $isPageBreakPreview? PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_BREAK_PREVIEW :
4284
- PHPExcel_Worksheet_SheetView::SHEETVIEW_NORMAL;
4285
- $this->_phpSheet->getSheetView()->setView($view);
4286
- if ($this->_version === self::XLS_BIFF8) {
4287
- $zoomScale = $isPageBreakPreview? $zoomscaleInPageBreakPreview : $zoomscaleInNormalView;
4288
- $this->_phpSheet->getSheetView()->setZoomScale($zoomScale);
4289
- $this->_phpSheet->getSheetView()->setZoomScaleNormal($zoomscaleInNormalView);
4290
- }
4291
- }
4292
- }
4293
-
4294
- /**
4295
- * Read PLV Record(Created by Excel2007 or upper)
4296
- */
4297
- private function _readPageLayoutView(){
4298
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4299
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4300
-
4301
- // move stream pointer to next record
4302
- $this->_pos += 4 + $length;
4303
-
4304
- //var_dump(unpack("vrt/vgrbitFrt/V2reserved/vwScalePLV/vgrbit", $recordData));
4305
-
4306
- // offset: 0; size: 2; rt
4307
- //->ignore
4308
- $rt = self::_GetInt2d($recordData, 0);
4309
- // offset: 2; size: 2; grbitfr
4310
- //->ignore
4311
- $grbitFrt = self::_GetInt2d($recordData, 2);
4312
- // offset: 4; size: 8; reserved
4313
- //->ignore
4314
-
4315
- // offset: 12; size 2; zoom scale
4316
- $wScalePLV = self::_GetInt2d($recordData, 12);
4317
- // offset: 14; size 2; grbit
4318
- $grbit = self::_GetInt2d($recordData, 14);
4319
-
4320
- // decomprise grbit
4321
- $fPageLayoutView = $grbit & 0x01;
4322
- $fRulerVisible = ($grbit >> 1) & 0x01; //no support
4323
- $fWhitespaceHidden = ($grbit >> 3) & 0x01; //no support
4324
-
4325
- if ($fPageLayoutView === 1) {
4326
- $this->_phpSheet->getSheetView()->setView(PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_LAYOUT);
4327
- $this->_phpSheet->getSheetView()->setZoomScale($wScalePLV); //set by Excel2007 only if SHEETVIEW_PAGE_LAYOUT
4328
- }
4329
- //otherwise, we cannot know whether SHEETVIEW_PAGE_LAYOUT or SHEETVIEW_PAGE_BREAK_PREVIEW.
4330
- }
4331
-
4332
- /**
4333
- * Read SCL record
4334
- */
4335
- private function _readScl()
4336
- {
4337
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4338
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4339
-
4340
- // move stream pointer to next record
4341
- $this->_pos += 4 + $length;
4342
-
4343
- // offset: 0; size: 2; numerator of the view magnification
4344
- $numerator = self::_GetInt2d($recordData, 0);
4345
-
4346
- // offset: 2; size: 2; numerator of the view magnification
4347
- $denumerator = self::_GetInt2d($recordData, 2);
4348
-
4349
- // set the zoom scale (in percent)
4350
- $this->_phpSheet->getSheetView()->setZoomScale($numerator * 100 / $denumerator);
4351
- }
4352
-
4353
-
4354
- /**
4355
- * Read PANE record
4356
- */
4357
- private function _readPane()
4358
- {
4359
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4360
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4361
-
4362
- // move stream pointer to next record
4363
- $this->_pos += 4 + $length;
4364
-
4365
- if (!$this->_readDataOnly) {
4366
- // offset: 0; size: 2; position of vertical split
4367
- $px = self::_GetInt2d($recordData, 0);
4368
-
4369
- // offset: 2; size: 2; position of horizontal split
4370
- $py = self::_GetInt2d($recordData, 2);
4371
-
4372
- if ($this->_frozen) {
4373
- // frozen panes
4374
- $this->_phpSheet->freezePane(PHPExcel_Cell::stringFromColumnIndex($px) . ($py + 1));
4375
- } else {
4376
- // unfrozen panes; split windows; not supported by PHPExcel core
4377
- }
4378
- }
4379
- }
4380
-
4381
-
4382
- /**
4383
- * Read SELECTION record. There is one such record for each pane in the sheet.
4384
- */
4385
- private function _readSelection()
4386
- {
4387
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4388
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4389
-
4390
- // move stream pointer to next record
4391
- $this->_pos += 4 + $length;
4392
-
4393
- if (!$this->_readDataOnly) {
4394
- // offset: 0; size: 1; pane identifier
4395
- $paneId = ord($recordData{0});
4396
-
4397
- // offset: 1; size: 2; index to row of the active cell
4398
- $r = self::_GetInt2d($recordData, 1);
4399
-
4400
- // offset: 3; size: 2; index to column of the active cell
4401
- $c = self::_GetInt2d($recordData, 3);
4402
-
4403
- // offset: 5; size: 2; index into the following cell range list to the
4404
- // entry that contains the active cell
4405
- $index = self::_GetInt2d($recordData, 5);
4406
-
4407
- // offset: 7; size: var; cell range address list containing all selected cell ranges
4408
- $data = substr($recordData, 7);
4409
- $cellRangeAddressList = $this->_readBIFF5CellRangeAddressList($data); // note: also BIFF8 uses BIFF5 syntax
4410
-
4411
- $selectedCells = $cellRangeAddressList['cellRangeAddresses'][0];
4412
-
4413
- // first row '1' + last row '16384' indicates that full column is selected (apparently also in BIFF8!)
4414
- if (preg_match('/^([A-Z]+1\:[A-Z]+)16384$/', $selectedCells)) {
4415
- $selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)16384$/', '${1}1048576', $selectedCells);
4416
- }
4417
-
4418
- // first row '1' + last row '65536' indicates that full column is selected
4419
- if (preg_match('/^([A-Z]+1\:[A-Z]+)65536$/', $selectedCells)) {
4420
- $selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)65536$/', '${1}1048576', $selectedCells);
4421
- }
4422
-
4423
- // first column 'A' + last column 'IV' indicates that full row is selected
4424
- if (preg_match('/^(A[0-9]+\:)IV([0-9]+)$/', $selectedCells)) {
4425
- $selectedCells = preg_replace('/^(A[0-9]+\:)IV([0-9]+)$/', '${1}XFD${2}', $selectedCells);
4426
- }
4427
-
4428
- $this->_phpSheet->setSelectedCells($selectedCells);
4429
- }
4430
- }
4431
-
4432
-
4433
- private function _includeCellRangeFiltered($cellRangeAddress)
4434
- {
4435
- $includeCellRange = true;
4436
- if ($this->getReadFilter() !== NULL) {
4437
- $includeCellRange = false;
4438
- $rangeBoundaries = PHPExcel_Cell::getRangeBoundaries($cellRangeAddress);
4439
- $rangeBoundaries[1][0]++;
4440
- for ($row = $rangeBoundaries[0][1]; $row <= $rangeBoundaries[1][1]; $row++) {
4441
- for ($column = $rangeBoundaries[0][0]; $column != $rangeBoundaries[1][0]; $column++) {
4442
- if ($this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle())) {
4443
- $includeCellRange = true;
4444
- break 2;
4445
- }
4446
- }
4447
- }
4448
- }
4449
- return $includeCellRange;
4450
- }
4451
-
4452
-
4453
- /**
4454
- * MERGEDCELLS
4455
- *
4456
- * This record contains the addresses of merged cell ranges
4457
- * in the current sheet.
4458
- *
4459
- * -- "OpenOffice.org's Documentation of the Microsoft
4460
- * Excel File Format"
4461
- */
4462
- private function _readMergedCells()
4463
- {
4464
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4465
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4466
-
4467
- // move stream pointer to next record
4468
- $this->_pos += 4 + $length;
4469
-
4470
- if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
4471
- $cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($recordData);
4472
- foreach ($cellRangeAddressList['cellRangeAddresses'] as $cellRangeAddress) {
4473
- if ((strpos($cellRangeAddress,':') !== FALSE) &&
4474
- ($this->_includeCellRangeFiltered($cellRangeAddress))) {
4475
- $this->_phpSheet->mergeCells($cellRangeAddress);
4476
- }
4477
- }
4478
- }
4479
- }
4480
-
4481
-
4482
- /**
4483
- * Read HYPERLINK record
4484
- */
4485
- private function _readHyperLink()
4486
- {
4487
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4488
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4489
-
4490
- // move stream pointer forward to next record
4491
- $this->_pos += 4 + $length;
4492
-
4493
- if (!$this->_readDataOnly) {
4494
- // offset: 0; size: 8; cell range address of all cells containing this hyperlink
4495
- try {
4496
- $cellRange = $this->_readBIFF8CellRangeAddressFixed($recordData, 0, 8);
4497
- } catch (PHPExcel_Exception $e) {
4498
- return;
4499
- }
4500
-
4501
- // offset: 8, size: 16; GUID of StdLink
4502
-
4503
- // offset: 24, size: 4; unknown value
4504
-
4505
- // offset: 28, size: 4; option flags
4506
-
4507
- // bit: 0; mask: 0x00000001; 0 = no link or extant, 1 = file link or URL
4508
- $isFileLinkOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 0;
4509
-
4510
- // bit: 1; mask: 0x00000002; 0 = relative path, 1 = absolute path or URL
4511
- $isAbsPathOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 1;
4512
-
4513
- // bit: 2 (and 4); mask: 0x00000014; 0 = no description
4514
- $hasDesc = (0x00000014 & self::_GetInt2d($recordData, 28)) >> 2;
4515
-
4516
- // bit: 3; mask: 0x00000008; 0 = no text, 1 = has text
4517
- $hasText = (0x00000008 & self::_GetInt2d($recordData, 28)) >> 3;
4518
-
4519
- // bit: 7; mask: 0x00000080; 0 = no target frame, 1 = has target frame
4520
- $hasFrame = (0x00000080 & self::_GetInt2d($recordData, 28)) >> 7;
4521
-
4522
- // bit: 8; mask: 0x00000100; 0 = file link or URL, 1 = UNC path (inc. server name)
4523
- $isUNC = (0x00000100 & self::_GetInt2d($recordData, 28)) >> 8;
4524
-
4525
- // offset within record data
4526
- $offset = 32;
4527
-
4528
- if ($hasDesc) {
4529
- // offset: 32; size: var; character count of description text
4530
- $dl = self::_GetInt4d($recordData, 32);
4531
- // offset: 36; size: var; character array of description text, no Unicode string header, always 16-bit characters, zero terminated
4532
- $desc = self::_encodeUTF16(substr($recordData, 36, 2 * ($dl - 1)), false);
4533
- $offset += 4 + 2 * $dl;
4534
- }
4535
- if ($hasFrame) {
4536
- $fl = self::_GetInt4d($recordData, $offset);
4537
- $offset += 4 + 2 * $fl;
4538
- }
4539
-
4540
- // detect type of hyperlink (there are 4 types)
4541
- $hyperlinkType = null;
4542
-
4543
- if ($isUNC) {
4544
- $hyperlinkType = 'UNC';
4545
- } else if (!$isFileLinkOrUrl) {
4546
- $hyperlinkType = 'workbook';
4547
- } else if (ord($recordData{$offset}) == 0x03) {
4548
- $hyperlinkType = 'local';
4549
- } else if (ord($recordData{$offset}) == 0xE0) {
4550
- $hyperlinkType = 'URL';
4551
- }
4552
-
4553
- switch ($hyperlinkType) {
4554
- case 'URL':
4555
- // section 5.58.2: Hyperlink containing a URL
4556
- // e.g. http://example.org/index.php
4557
-
4558
- // offset: var; size: 16; GUID of URL Moniker
4559
- $offset += 16;
4560
- // offset: var; size: 4; size (in bytes) of character array of the URL including trailing zero word
4561
- $us = self::_GetInt4d($recordData, $offset);
4562
- $offset += 4;
4563
- // offset: var; size: $us; character array of the URL, no Unicode string header, always 16-bit characters, zero-terminated
4564
- $url = self::_encodeUTF16(substr($recordData, $offset, $us - 2), false);
4565
- $nullOffset = strpos($url, 0x00);
4566
- if ($nullOffset)
4567
- $url = substr($url,0,$nullOffset);
4568
- $url .= $hasText ? '#' : '';
4569
- $offset += $us;
4570
- break;
4571
-
4572
- case 'local':
4573
- // section 5.58.3: Hyperlink to local file
4574
- // examples:
4575
- // mydoc.txt
4576
- // ../../somedoc.xls#Sheet!A1
4577
-
4578
- // offset: var; size: 16; GUI of File Moniker
4579
- $offset += 16;
4580
-
4581
- // offset: var; size: 2; directory up-level count.
4582
- $upLevelCount = self::_GetInt2d($recordData, $offset);
4583
- $offset += 2;
4584
-
4585
- // offset: var; size: 4; character count of the shortened file path and name, including trailing zero word
4586
- $sl = self::_GetInt4d($recordData, $offset);
4587
- $offset += 4;
4588
-
4589
- // offset: var; size: sl; character array of the shortened file path and name in 8.3-DOS-format (compressed Unicode string)
4590
- $shortenedFilePath = substr($recordData, $offset, $sl);
4591
- $shortenedFilePath = self::_encodeUTF16($shortenedFilePath, true);
4592
- $shortenedFilePath = substr($shortenedFilePath, 0, -1); // remove trailing zero
4593
-
4594
- $offset += $sl;
4595
-
4596
- // offset: var; size: 24; unknown sequence
4597
- $offset += 24;
4598
-
4599
- // extended file path
4600
- // offset: var; size: 4; size of the following file link field including string lenth mark
4601
- $sz = self::_GetInt4d($recordData, $offset);
4602
- $offset += 4;
4603
-
4604
- // only present if $sz > 0
4605
- if ($sz > 0) {
4606
- // offset: var; size: 4; size of the character array of the extended file path and name
4607
- $xl = self::_GetInt4d($recordData, $offset);
4608
- $offset += 4;
4609
-
4610
- // offset: var; size 2; unknown
4611
- $offset += 2;
4612
-
4613
- // offset: var; size $xl; character array of the extended file path and name.
4614
- $extendedFilePath = substr($recordData, $offset, $xl);
4615
- $extendedFilePath = self::_encodeUTF16($extendedFilePath, false);
4616
- $offset += $xl;
4617
- }
4618
-
4619
- // construct the path
4620
- $url = str_repeat('..\\', $upLevelCount);
4621
- $url .= ($sz > 0) ?
4622
- $extendedFilePath : $shortenedFilePath; // use extended path if available
4623
- $url .= $hasText ? '#' : '';
4624
-
4625
- break;
4626
-
4627
-
4628
- case 'UNC':
4629
- // section 5.58.4: Hyperlink to a File with UNC (Universal Naming Convention) Path
4630
- // todo: implement
4631
- return;
4632
-
4633
- case 'workbook':
4634
- // section 5.58.5: Hyperlink to the Current Workbook
4635
- // e.g. Sheet2!B1:C2, stored in text mark field
4636
- $url = 'sheet://';
4637
- break;
4638
-
4639
- default:
4640
- return;
4641
-
4642
- }
4643
-
4644
- if ($hasText) {
4645
- // offset: var; size: 4; character count of text mark including trailing zero word
4646
- $tl = self::_GetInt4d($recordData, $offset);
4647
- $offset += 4;
4648
- // offset: var; size: var; character array of the text mark without the # sign, no Unicode header, always 16-bit characters, zero-terminated
4649
- $text = self::_encodeUTF16(substr($recordData, $offset, 2 * ($tl - 1)), false);
4650
- $url .= $text;
4651
- }
4652
-
4653
- // apply the hyperlink to all the relevant cells
4654
- foreach (PHPExcel_Cell::extractAllCellReferencesInRange($cellRange) as $coordinate) {
4655
- $this->_phpSheet->getCell($coordinate)->getHyperLink()->setUrl($url);
4656
- }
4657
- }
4658
- }
4659
-
4660
-
4661
- /**
4662
- * Read DATAVALIDATIONS record
4663
- */
4664
- private function _readDataValidations()
4665
- {
4666
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4667
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4668
-
4669
- // move stream pointer forward to next record
4670
- $this->_pos += 4 + $length;
4671
- }
4672
-
4673
-
4674
- /**
4675
- * Read DATAVALIDATION record
4676
- */
4677
- private function _readDataValidation()
4678
- {
4679
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4680
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4681
-
4682
- // move stream pointer forward to next record
4683
- $this->_pos += 4 + $length;
4684
-
4685
- if ($this->_readDataOnly) {
4686
- return;
4687
- }
4688
-
4689
- // offset: 0; size: 4; Options
4690
- $options = self::_GetInt4d($recordData, 0);
4691
-
4692
- // bit: 0-3; mask: 0x0000000F; type
4693
- $type = (0x0000000F & $options) >> 0;
4694
- switch ($type) {
4695
- case 0x00: $type = PHPExcel_Cell_DataValidation::TYPE_NONE; break;
4696
- case 0x01: $type = PHPExcel_Cell_DataValidation::TYPE_WHOLE; break;
4697
- case 0x02: $type = PHPExcel_Cell_DataValidation::TYPE_DECIMAL; break;
4698
- case 0x03: $type = PHPExcel_Cell_DataValidation::TYPE_LIST; break;
4699
- case 0x04: $type = PHPExcel_Cell_DataValidation::TYPE_DATE; break;
4700
- case 0x05: $type = PHPExcel_Cell_DataValidation::TYPE_TIME; break;
4701
- case 0x06: $type = PHPExcel_Cell_DataValidation::TYPE_TEXTLENGTH; break;
4702
- case 0x07: $type = PHPExcel_Cell_DataValidation::TYPE_CUSTOM; break;
4703
- }
4704
-
4705
- // bit: 4-6; mask: 0x00000070; error type
4706
- $errorStyle = (0x00000070 & $options) >> 4;
4707
- switch ($errorStyle) {
4708
- case 0x00: $errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP; break;
4709
- case 0x01: $errorStyle = PHPExcel_Cell_DataValidation::STYLE_WARNING; break;
4710
- case 0x02: $errorStyle = PHPExcel_Cell_DataValidation::STYLE_INFORMATION; break;
4711
- }
4712
-
4713
- // bit: 7; mask: 0x00000080; 1= formula is explicit (only applies to list)
4714
- // I have only seen cases where this is 1
4715
- $explicitFormula = (0x00000080 & $options) >> 7;
4716
-
4717
- // bit: 8; mask: 0x00000100; 1= empty cells allowed
4718
- $allowBlank = (0x00000100 & $options) >> 8;
4719
-
4720
- // bit: 9; mask: 0x00000200; 1= suppress drop down arrow in list type validity
4721
- $suppressDropDown = (0x00000200 & $options) >> 9;
4722
-
4723
- // bit: 18; mask: 0x00040000; 1= show prompt box if cell selected
4724
- $showInputMessage = (0x00040000 & $options) >> 18;
4725
-
4726
- // bit: 19; mask: 0x00080000; 1= show error box if invalid values entered
4727
- $showErrorMessage = (0x00080000 & $options) >> 19;
4728
-
4729
- // bit: 20-23; mask: 0x00F00000; condition operator
4730
- $operator = (0x00F00000 & $options) >> 20;
4731
- switch ($operator) {
4732
- case 0x00: $operator = PHPExcel_Cell_DataValidation::OPERATOR_BETWEEN ; break;
4733
- case 0x01: $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTBETWEEN ; break;
4734
- case 0x02: $operator = PHPExcel_Cell_DataValidation::OPERATOR_EQUAL ; break;
4735
- case 0x03: $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTEQUAL ; break;
4736
- case 0x04: $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHAN ; break;
4737
- case 0x05: $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHAN ; break;
4738
- case 0x06: $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHANOREQUAL; break;
4739
- case 0x07: $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHANOREQUAL ; break;
4740
- }
4741
-
4742
- // offset: 4; size: var; title of the prompt box
4743
- $offset = 4;
4744
- $string = self::_readUnicodeStringLong(substr($recordData, $offset));
4745
- $promptTitle = $string['value'] !== chr(0) ?
4746
- $string['value'] : '';
4747
- $offset += $string['size'];
4748
-
4749
- // offset: var; size: var; title of the error box
4750
- $string = self::_readUnicodeStringLong(substr($recordData, $offset));
4751
- $errorTitle = $string['value'] !== chr(0) ?
4752
- $string['value'] : '';
4753
- $offset += $string['size'];
4754
-
4755
- // offset: var; size: var; text of the prompt box
4756
- $string = self::_readUnicodeStringLong(substr($recordData, $offset));
4757
- $prompt = $string['value'] !== chr(0) ?
4758
- $string['value'] : '';
4759
- $offset += $string['size'];
4760
-
4761
- // offset: var; size: var; text of the error box
4762
- $string = self::_readUnicodeStringLong(substr($recordData, $offset));
4763
- $error = $string['value'] !== chr(0) ?
4764
- $string['value'] : '';
4765
- $offset += $string['size'];
4766
-
4767
- // offset: var; size: 2; size of the formula data for the first condition
4768
- $sz1 = self::_GetInt2d($recordData, $offset);
4769
- $offset += 2;
4770
-
4771
- // offset: var; size: 2; not used
4772
- $offset += 2;
4773
-
4774
- // offset: var; size: $sz1; formula data for first condition (without size field)
4775
- $formula1 = substr($recordData, $offset, $sz1);
4776
- $formula1 = pack('v', $sz1) . $formula1; // prepend the length
4777
- try {
4778
- $formula1 = $this->_getFormulaFromStructure($formula1);
4779
-
4780
- // in list type validity, null characters are used as item separators
4781
- if ($type == PHPExcel_Cell_DataValidation::TYPE_LIST) {
4782
- $formula1 = str_replace(chr(0), ',', $formula1);
4783
- }
4784
- } catch (PHPExcel_Exception $e) {
4785
- return;
4786
- }
4787
- $offset += $sz1;
4788
-
4789
- // offset: var; size: 2; size of the formula data for the first condition
4790
- $sz2 = self::_GetInt2d($recordData, $offset);
4791
- $offset += 2;
4792
-
4793
- // offset: var; size: 2; not used
4794
- $offset += 2;
4795
-
4796
- // offset: var; size: $sz2; formula data for second condition (without size field)
4797
- $formula2 = substr($recordData, $offset, $sz2);
4798
- $formula2 = pack('v', $sz2) . $formula2; // prepend the length
4799
- try {
4800
- $formula2 = $this->_getFormulaFromStructure($formula2);
4801
- } catch (PHPExcel_Exception $e) {
4802
- return;
4803
- }
4804
- $offset += $sz2;
4805
-
4806
- // offset: var; size: var; cell range address list with
4807
- $cellRangeAddressList = $this->_readBIFF8CellRangeAddressList(substr($recordData, $offset));
4808
- $cellRangeAddresses = $cellRangeAddressList['cellRangeAddresses'];
4809
-
4810
- foreach ($cellRangeAddresses as $cellRange) {
4811
- $stRange = $this->_phpSheet->shrinkRangeToFit($cellRange);
4812
- $stRange = PHPExcel_Cell::extractAllCellReferencesInRange($stRange);
4813
- foreach ($stRange as $coordinate) {
4814
- $objValidation = $this->_phpSheet->getCell($coordinate)->getDataValidation();
4815
- $objValidation->setType($type);
4816
- $objValidation->setErrorStyle($errorStyle);
4817
- $objValidation->setAllowBlank((bool)$allowBlank);
4818
- $objValidation->setShowInputMessage((bool)$showInputMessage);
4819
- $objValidation->setShowErrorMessage((bool)$showErrorMessage);
4820
- $objValidation->setShowDropDown(!$suppressDropDown);
4821
- $objValidation->setOperator($operator);
4822
- $objValidation->setErrorTitle($errorTitle);
4823
- $objValidation->setError($error);
4824
- $objValidation->setPromptTitle($promptTitle);
4825
- $objValidation->setPrompt($prompt);
4826
- $objValidation->setFormula1($formula1);
4827
- $objValidation->setFormula2($formula2);
4828
- }
4829
- }
4830
-
4831
- }
4832
-
4833
-
4834
- /**
4835
- * Read SHEETLAYOUT record. Stores sheet tab color information.
4836
- */
4837
- private function _readSheetLayout()
4838
- {
4839
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4840
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4841
-
4842
- // move stream pointer to next record
4843
- $this->_pos += 4 + $length;
4844
-
4845
- // local pointer in record data
4846
- $offset = 0;
4847
-
4848
- if (!$this->_readDataOnly) {
4849
- // offset: 0; size: 2; repeated record identifier 0x0862
4850
-
4851
- // offset: 2; size: 10; not used
4852
-
4853
- // offset: 12; size: 4; size of record data
4854
- // Excel 2003 uses size of 0x14 (documented), Excel 2007 uses size of 0x28 (not documented?)
4855
- $sz = self::_GetInt4d($recordData, 12);
4856
-
4857
- switch ($sz) {
4858
- case 0x14:
4859
- // offset: 16; size: 2; color index for sheet tab
4860
- $colorIndex = self::_GetInt2d($recordData, 16);
4861
- $color = self::_readColor($colorIndex,$this->_palette,$this->_version);
4862
- $this->_phpSheet->getTabColor()->setRGB($color['rgb']);
4863
- break;
4864
-
4865
- case 0x28:
4866
- // TODO: Investigate structure for .xls SHEETLAYOUT record as saved by MS Office Excel 2007
4867
- return;
4868
- break;
4869
- }
4870
- }
4871
- }
4872
-
4873
-
4874
- /**
4875
- * Read SHEETPROTECTION record (FEATHEADR)
4876
- */
4877
- private function _readSheetProtection()
4878
- {
4879
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4880
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4881
-
4882
- // move stream pointer to next record
4883
- $this->_pos += 4 + $length;
4884
-
4885
- if ($this->_readDataOnly) {
4886
- return;
4887
- }
4888
-
4889
- // offset: 0; size: 2; repeated record header
4890
-
4891
- // offset: 2; size: 2; FRT cell reference flag (=0 currently)
4892
-
4893
- // offset: 4; size: 8; Currently not used and set to 0
4894
-
4895
- // offset: 12; size: 2; Shared feature type index (2=Enhanced Protetion, 4=SmartTag)
4896
- $isf = self::_GetInt2d($recordData, 12);
4897
- if ($isf != 2) {
4898
- return;
4899
- }
4900
-
4901
- // offset: 14; size: 1; =1 since this is a feat header
4902
-
4903
- // offset: 15; size: 4; size of rgbHdrSData
4904
-
4905
- // rgbHdrSData, assume "Enhanced Protection"
4906
- // offset: 19; size: 2; option flags
4907
- $options = self::_GetInt2d($recordData, 19);
4908
-
4909
- // bit: 0; mask 0x0001; 1 = user may edit objects, 0 = users must not edit objects
4910
- $bool = (0x0001 & $options) >> 0;
4911
- $this->_phpSheet->getProtection()->setObjects(!$bool);
4912
-
4913
- // bit: 1; mask 0x0002; edit scenarios
4914
- $bool = (0x0002 & $options) >> 1;
4915
- $this->_phpSheet->getProtection()->setScenarios(!$bool);
4916
-
4917
- // bit: 2; mask 0x0004; format cells
4918
- $bool = (0x0004 & $options) >> 2;
4919
- $this->_phpSheet->getProtection()->setFormatCells(!$bool);
4920
-
4921
- // bit: 3; mask 0x0008; format columns
4922
- $bool = (0x0008 & $options) >> 3;
4923
- $this->_phpSheet->getProtection()->setFormatColumns(!$bool);
4924
-
4925
- // bit: 4; mask 0x0010; format rows
4926
- $bool = (0x0010 & $options) >> 4;
4927
- $this->_phpSheet->getProtection()->setFormatRows(!$bool);
4928
-
4929
- // bit: 5; mask 0x0020; insert columns
4930
- $bool = (0x0020 & $options) >> 5;
4931
- $this->_phpSheet->getProtection()->setInsertColumns(!$bool);
4932
-
4933
- // bit: 6; mask 0x0040; insert rows
4934
- $bool = (0x0040 & $options) >> 6;
4935
- $this->_phpSheet->getProtection()->setInsertRows(!$bool);
4936
-
4937
- // bit: 7; mask 0x0080; insert hyperlinks
4938
- $bool = (0x0080 & $options) >> 7;
4939
- $this->_phpSheet->getProtection()->setInsertHyperlinks(!$bool);
4940
-
4941
- // bit: 8; mask 0x0100; delete columns
4942
- $bool = (0x0100 & $options) >> 8;
4943
- $this->_phpSheet->getProtection()->setDeleteColumns(!$bool);
4944
-
4945
- // bit: 9; mask 0x0200; delete rows
4946
- $bool = (0x0200 & $options) >> 9;
4947
- $this->_phpSheet->getProtection()->setDeleteRows(!$bool);
4948
-
4949
- // bit: 10; mask 0x0400; select locked cells
4950
- $bool = (0x0400 & $options) >> 10;
4951
- $this->_phpSheet->getProtection()->setSelectLockedCells(!$bool);
4952
-
4953
- // bit: 11; mask 0x0800; sort cell range
4954
- $bool = (0x0800 & $options) >> 11;
4955
- $this->_phpSheet->getProtection()->setSort(!$bool);
4956
-
4957
- // bit: 12; mask 0x1000; auto filter
4958
- $bool = (0x1000 & $options) >> 12;
4959
- $this->_phpSheet->getProtection()->setAutoFilter(!$bool);
4960
-
4961
- // bit: 13; mask 0x2000; pivot tables
4962
- $bool = (0x2000 & $options) >> 13;
4963
- $this->_phpSheet->getProtection()->setPivotTables(!$bool);
4964
-
4965
- // bit: 14; mask 0x4000; select unlocked cells
4966
- $bool = (0x4000 & $options) >> 14;
4967
- $this->_phpSheet->getProtection()->setSelectUnlockedCells(!$bool);
4968
-
4969
- // offset: 21; size: 2; not used
4970
- }
4971
-
4972
-
4973
- /**
4974
- * Read RANGEPROTECTION record
4975
- * Reading of this record is based on Microsoft Office Excel 97-2000 Binary File Format Specification,
4976
- * where it is referred to as FEAT record
4977
- */
4978
- private function _readRangeProtection()
4979
- {
4980
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4981
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4982
-
4983
- // move stream pointer to next record
4984
- $this->_pos += 4 + $length;
4985
-
4986
- // local pointer in record data
4987
- $offset = 0;
4988
-
4989
- if (!$this->_readDataOnly) {
4990
- $offset += 12;
4991
-
4992
- // offset: 12; size: 2; shared feature type, 2 = enhanced protection, 4 = smart tag
4993
- $isf = self::_GetInt2d($recordData, 12);
4994
- if ($isf != 2) {
4995
- // we only read FEAT records of type 2
4996
- return;
4997
- }
4998
- $offset += 2;
4999
-
5000
- $offset += 5;
5001
-
5002
- // offset: 19; size: 2; count of ref ranges this feature is on
5003
- $cref = self::_GetInt2d($recordData, 19);
5004
- $offset += 2;
5005
-
5006
- $offset += 6;
5007
-
5008
- // offset: 27; size: 8 * $cref; list of cell ranges (like in hyperlink record)
5009
- $cellRanges = array();
5010
- for ($i = 0; $i < $cref; ++$i) {
5011
- try {
5012
- $cellRange = $this->_readBIFF8CellRangeAddressFixed(substr($recordData, 27 + 8 * $i, 8));
5013
- } catch (PHPExcel_Exception $e) {
5014
- return;
5015
- }
5016
- $cellRanges[] = $cellRange;
5017
- $offset += 8;
5018
- }
5019
-
5020
- // offset: var; size: var; variable length of feature specific data
5021
- $rgbFeat = substr($recordData, $offset);
5022
- $offset += 4;
5023
-
5024
- // offset: var; size: 4; the encrypted password (only 16-bit although field is 32-bit)
5025
- $wPassword = self::_GetInt4d($recordData, $offset);
5026
- $offset += 4;
5027
-
5028
- // Apply range protection to sheet
5029
- if ($cellRanges) {
5030
- $this->_phpSheet->protectCells(implode(' ', $cellRanges), strtoupper(dechex($wPassword)), true);
5031
- }
5032
- }
5033
- }
5034
-
5035
-
5036
- /**
5037
- * Read IMDATA record
5038
- */
5039
- private function _readImData()
5040
- {
5041
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
5042
-
5043
- // get spliced record data
5044
- $splicedRecordData = $this->_getSplicedRecordData();
5045
- $recordData = $splicedRecordData['recordData'];
5046
-
5047
- // UNDER CONSTRUCTION
5048
-
5049
- // offset: 0; size: 2; image format
5050
- $cf = self::_GetInt2d($recordData, 0);
5051
-
5052
- // offset: 2; size: 2; environment from which the file was written
5053
- $env = self::_GetInt2d($recordData, 2);
5054
-
5055
- // offset: 4; size: 4; length of the image data
5056
- $lcb = self::_GetInt4d($recordData, 4);
5057
-
5058
- // offset: 8; size: var; image data
5059
- $iData = substr($recordData, 8);
5060
-
5061
- switch ($cf) {
5062
- case 0x09: // Windows bitmap format
5063
- // BITMAPCOREINFO
5064
- // 1. BITMAPCOREHEADER
5065
- // offset: 0; size: 4; bcSize, Specifies the number of bytes required by the structure
5066
- $bcSize = self::_GetInt4d($iData, 0);
5067
- // var_dump($bcSize);
5068
-
5069
- // offset: 4; size: 2; bcWidth, specifies the width of the bitmap, in pixels
5070
- $bcWidth = self::_GetInt2d($iData, 4);
5071
- // var_dump($bcWidth);
5072
-
5073
- // offset: 6; size: 2; bcHeight, specifies the height of the bitmap, in pixels.
5074
- $bcHeight = self::_GetInt2d($iData, 6);
5075
- // var_dump($bcHeight);
5076
- $ih = imagecreatetruecolor($bcWidth, $bcHeight);
5077
-
5078
- // offset: 8; size: 2; bcPlanes, specifies the number of planes for the target device. This value must be 1
5079
-
5080
- // offset: 10; size: 2; bcBitCount specifies the number of bits-per-pixel. This value must be 1, 4, 8, or 24
5081
- $bcBitCount = self::_GetInt2d($iData, 10);
5082
- // var_dump($bcBitCount);
5083
-
5084
- $rgbString = substr($iData, 12);
5085
- $rgbTriples = array();
5086
- while (strlen($rgbString) > 0) {
5087
- $rgbTriples[] = unpack('Cb/Cg/Cr', $rgbString);
5088
- $rgbString = substr($rgbString, 3);
5089
- }
5090
- $x = 0;
5091
- $y = 0;
5092
- foreach ($rgbTriples as $i => $rgbTriple) {
5093
- $color = imagecolorallocate($ih, $rgbTriple['r'], $rgbTriple['g'], $rgbTriple['b']);
5094
- imagesetpixel($ih, $x, $bcHeight - 1 - $y, $color);
5095
- $x = ($x + 1) % $bcWidth;
5096
- $y = $y + floor(($x + 1) / $bcWidth);
5097
- }
5098
- //imagepng($ih, 'image.png');
5099
-
5100
- $drawing = new PHPExcel_Worksheet_Drawing();
5101
- $drawing->setPath($filename);
5102
- $drawing->setWorksheet($this->_phpSheet);
5103
-
5104
- break;
5105
-
5106
- case 0x02: // Windows metafile or Macintosh PICT format
5107
- case 0x0e: // native format
5108
- default;
5109
- break;
5110
-
5111
- }
5112
-
5113
- // _getSplicedRecordData() takes care of moving current position in data stream
5114
- }
5115
-
5116
-
5117
- /**
5118
- * Read a free CONTINUE record. Free CONTINUE record may be a camouflaged MSODRAWING record
5119
- * When MSODRAWING data on a sheet exceeds 8224 bytes, CONTINUE records are used instead. Undocumented.
5120
- * In this case, we must treat the CONTINUE record as a MSODRAWING record
5121
- */
5122
- private function _readContinue()
5123
- {
5124
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
5125
- $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
5126
-
5127
- // check if we are reading drawing data
5128
- // this is in case a free CONTINUE record occurs in other circumstances we are unaware of
5129
- if ($this->_drawingData == '') {
5130
- // move stream pointer to next record
5131
- $this->_pos += 4 + $length;
5132
-
5133
- return;
5134
- }
5135
-
5136
- // check if record data is at least 4 bytes long, otherwise there is no chance this is MSODRAWING data
5137
- if ($length < 4) {
5138
- // move stream pointer to next record
5139
- $this->_pos += 4 + $length;
5140
-
5141
- return;
5142
- }
5143
-
5144
- // dirty check to see if CONTINUE record could be a camouflaged MSODRAWING record
5145
- // look inside CONTINUE record to see if it looks like a part of an Escher stream
5146
- // we know that Escher stream may be split at least at
5147
- // 0xF003 MsofbtSpgrContainer
5148
- // 0xF004 MsofbtSpContainer
5149
- // 0xF00D MsofbtClientTextbox
5150
- $validSplitPoints = array(0xF003, 0xF004, 0xF00D); // add identifiers if we find more
5151
-
5152
- $splitPoint = self::_GetInt2d($recordData, 2);
5153
- if (in_array($splitPoint, $validSplitPoints)) {
5154
- // get spliced record data (and move pointer to next record)
5155
- $splicedRecordData = $this->_getSplicedRecordData();
5156
- $this->_drawingData .= $splicedRecordData['recordData'];
5157
-
5158
- return;
5159
- }
5160
-
5161
- // move stream pointer to next record
5162
- $this->_pos += 4 + $length;
5163
-
5164
- }
5165
-
5166
-
5167
- /**
5168
- * Reads a record from current position in data stream and continues reading data as long as CONTINUE
5169
- * records are found. Splices the record data pieces and returns the combined string as if record data
5170
- * is in one piece.
5171
- * Moves to next current position in data stream to start of next record different from a CONtINUE record
5172
- *
5173
- * @return array
5174
- */
5175
- private function _getSplicedRecordData()
5176
- {
5177
- $data = '';
5178
- $spliceOffsets = array();
5179
-
5180
- $i = 0;
5181
- $spliceOffsets[0] = 0;
5182
-
5183
- do {
5184
- ++$i;
5185
-
5186
- // offset: 0; size: 2; identifier
5187
- $identifier = self::_GetInt2d($this->_data, $this->_pos);
5188
- // offset: 2; size: 2; length
5189
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
5190
- $data .= $this->_readRecordData($this->_data, $this->_pos + 4, $length);
5191
-
5192
- $spliceOffsets[$i] = $spliceOffsets[$i - 1] + $length;
5193
-
5194
- $this->_pos += 4 + $length;
5195
- $nextIdentifier = self::_GetInt2d($this->_data, $this->_pos);
5196
- }
5197
- while ($nextIdentifier == self::XLS_Type_CONTINUE);
5198
-
5199
- $splicedData = array(
5200
- 'recordData' => $data,
5201
- 'spliceOffsets' => $spliceOffsets,
5202
- );
5203
-
5204
- return $splicedData;
5205
-
5206
- }
5207
-
5208
-
5209
- /**
5210
- * Convert formula structure into human readable Excel formula like 'A3+A5*5'
5211
- *
5212
- * @param string $formulaStructure The complete binary data for the formula
5213
- * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5214
- * @return string Human readable formula
5215
- */
5216
- private function _getFormulaFromStructure($formulaStructure, $baseCell = 'A1')
5217
- {
5218
- // offset: 0; size: 2; size of the following formula data
5219
- $sz = self::_GetInt2d($formulaStructure, 0);
5220
-
5221
- // offset: 2; size: sz
5222
- $formulaData = substr($formulaStructure, 2, $sz);
5223
-
5224
- // for debug: dump the formula data
5225
- //echo '<xmp>';
5226
- //echo 'size: ' . $sz . "\n";
5227
- //echo 'the entire formula data: ';
5228
- //Debug::dump($formulaData);
5229
- //echo "\n----\n";
5230
-
5231
- // offset: 2 + sz; size: variable (optional)
5232
- if (strlen($formulaStructure) > 2 + $sz) {
5233
- $additionalData = substr($formulaStructure, 2 + $sz);
5234
-
5235
- // for debug: dump the additional data
5236
- //echo 'the entire additional data: ';
5237
- //Debug::dump($additionalData);
5238
- //echo "\n----\n";
5239
-
5240
- } else {
5241
- $additionalData = '';
5242
- }
5243
-
5244
- return $this->_getFormulaFromData($formulaData, $additionalData, $baseCell);
5245
- }
5246
-
5247
-
5248
- /**
5249
- * Take formula data and additional data for formula and return human readable formula
5250
- *
5251
- * @param string $formulaData The binary data for the formula itself
5252
- * @param string $additionalData Additional binary data going with the formula
5253
- * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5254
- * @return string Human readable formula
5255
- */
5256
- private function _getFormulaFromData($formulaData, $additionalData = '', $baseCell = 'A1')
5257
- {
5258
- // start parsing the formula data
5259
- $tokens = array();
5260
-
5261
- while (strlen($formulaData) > 0 and $token = $this->_getNextToken($formulaData, $baseCell)) {
5262
- $tokens[] = $token;
5263
- $formulaData = substr($formulaData, $token['size']);
5264
-
5265
- // for debug: dump the token
5266
- //var_dump($token);
5267
- }
5268
-
5269
- $formulaString = $this->_createFormulaFromTokens($tokens, $additionalData);
5270
-
5271
- return $formulaString;
5272
- }
5273
-
5274
-
5275
- /**
5276
- * Take array of tokens together with additional data for formula and return human readable formula
5277
- *
5278
- * @param array $tokens
5279
- * @param array $additionalData Additional binary data going with the formula
5280
- * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5281
- * @return string Human readable formula
5282
- */
5283
- private function _createFormulaFromTokens($tokens, $additionalData)
5284
- {
5285
- // empty formula?
5286
- if (empty($tokens)) {
5287
- return '';
5288
- }
5289
-
5290
- $formulaStrings = array();
5291
- foreach ($tokens as $token) {
5292
- // initialize spaces
5293
- $space0 = isset($space0) ? $space0 : ''; // spaces before next token, not tParen
5294
- $space1 = isset($space1) ? $space1 : ''; // carriage returns before next token, not tParen
5295
- $space2 = isset($space2) ? $space2 : ''; // spaces before opening parenthesis
5296
- $space3 = isset($space3) ? $space3 : ''; // carriage returns before opening parenthesis
5297
- $space4 = isset($space4) ? $space4 : ''; // spaces before closing parenthesis
5298
- $space5 = isset($space5) ? $space5 : ''; // carriage returns before closing parenthesis
5299
-
5300
- switch ($token['name']) {
5301
- case 'tAdd': // addition
5302
- case 'tConcat': // addition
5303
- case 'tDiv': // division
5304
- case 'tEQ': // equality
5305
- case 'tGE': // greater than or equal
5306
- case 'tGT': // greater than
5307
- case 'tIsect': // intersection
5308
- case 'tLE': // less than or equal
5309
- case 'tList': // less than or equal
5310
- case 'tLT': // less than
5311
- case 'tMul': // multiplication
5312
- case 'tNE': // multiplication
5313
- case 'tPower': // power
5314
- case 'tRange': // range
5315
- case 'tSub': // subtraction
5316
- $op2 = array_pop($formulaStrings);
5317
- $op1 = array_pop($formulaStrings);
5318
- $formulaStrings[] = "$op1$space1$space0{$token['data']}$op2";
5319
- unset($space0, $space1);
5320
- break;
5321
- case 'tUplus': // unary plus
5322
- case 'tUminus': // unary minus
5323
- $op = array_pop($formulaStrings);
5324
- $formulaStrings[] = "$space1$space0{$token['data']}$op";
5325
- unset($space0, $space1);
5326
- break;
5327
- case 'tPercent': // percent sign
5328
- $op = array_pop($formulaStrings);
5329
- $formulaStrings[] = "$op$space1$space0{$token['data']}";
5330
- unset($space0, $space1);
5331
- break;
5332
- case 'tAttrVolatile': // indicates volatile function
5333
- case 'tAttrIf':
5334
- case 'tAttrSkip':
5335
- case 'tAttrChoose':
5336
- // token is only important for Excel formula evaluator
5337
- // do nothing
5338
- break;
5339
- case 'tAttrSpace': // space / carriage return
5340
- // space will be used when next token arrives, do not alter formulaString stack
5341
- switch ($token['data']['spacetype']) {
5342
- case 'type0':
5343
- $space0 = str_repeat(' ', $token['data']['spacecount']);
5344
- break;
5345
- case 'type1':
5346
- $space1 = str_repeat("\n", $token['data']['spacecount']);
5347
- break;
5348
- case 'type2':
5349
- $space2 = str_repeat(' ', $token['data']['spacecount']);
5350
- break;
5351
- case 'type3':
5352
- $space3 = str_repeat("\n", $token['data']['spacecount']);
5353
- break;
5354
- case 'type4':
5355
- $space4 = str_repeat(' ', $token['data']['spacecount']);
5356
- break;
5357
- case 'type5':
5358
- $space5 = str_repeat("\n", $token['data']['spacecount']);
5359
- break;
5360
- }
5361
- break;
5362
- case 'tAttrSum': // SUM function with one parameter
5363
- $op = array_pop($formulaStrings);
5364
- $formulaStrings[] = "{$space1}{$space0}SUM($op)";
5365
- unset($space0, $space1);
5366
- break;
5367
- case 'tFunc': // function with fixed number of arguments
5368
- case 'tFuncV': // function with variable number of arguments
5369
- if ($token['data']['function'] != '') {
5370
- // normal function
5371
- $ops = array(); // array of operators
5372
- for ($i = 0; $i < $token['data']['args']; ++$i) {
5373
- $ops[] = array_pop($formulaStrings);
5374
- }
5375
- $ops = array_reverse($ops);
5376
- $formulaStrings[] = "$space1$space0{$token['data']['function']}(" . implode(',', $ops) . ")";
5377
- unset($space0, $space1);
5378
- } else {
5379
- // add-in function
5380
- $ops = array(); // array of operators
5381
- for ($i = 0; $i < $token['data']['args'] - 1; ++$i) {
5382
- $ops[] = array_pop($formulaStrings);
5383
- }
5384
- $ops = array_reverse($ops);
5385
- $function = array_pop($formulaStrings);
5386
- $formulaStrings[] = "$space1$space0$function(" . implode(',', $ops) . ")";
5387
- unset($space0, $space1);
5388
- }
5389
- break;
5390
- case 'tParen': // parenthesis
5391
- $expression = array_pop($formulaStrings);
5392
- $formulaStrings[] = "$space3$space2($expression$space5$space4)";
5393
- unset($space2, $space3, $space4, $space5);
5394
- break;
5395
- case 'tArray': // array constant
5396
- $constantArray = self::_readBIFF8ConstantArray($additionalData);
5397
- $formulaStrings[] = $space1 . $space0 . $constantArray['value'];
5398
- $additionalData = substr($additionalData, $constantArray['size']); // bite of chunk of additional data
5399
- unset($space0, $space1);
5400
- break;
5401
- case 'tMemArea':
5402
- // bite off chunk of additional data
5403
- $cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($additionalData);
5404
- $additionalData = substr($additionalData, $cellRangeAddressList['size']);
5405
- $formulaStrings[] = "$space1$space0{$token['data']}";
5406
- unset($space0, $space1);
5407
- break;
5408
- case 'tArea': // cell range address
5409
- case 'tBool': // boolean
5410
- case 'tErr': // error code
5411
- case 'tInt': // integer
5412
- case 'tMemErr':
5413
- case 'tMemFunc':
5414
- case 'tMissArg':
5415
- case 'tName':
5416
- case 'tNameX':
5417
- case 'tNum': // number
5418
- case 'tRef': // single cell reference
5419
- case 'tRef3d': // 3d cell reference
5420
- case 'tArea3d': // 3d cell range reference
5421
- case 'tRefN':
5422
- case 'tAreaN':
5423
- case 'tStr': // string
5424
- $formulaStrings[] = "$space1$space0{$token['data']}";
5425
- unset($space0, $space1);
5426
- break;
5427
- }
5428
- }
5429
- $formulaString = $formulaStrings[0];
5430
-
5431
- // for debug: dump the human readable formula
5432
- //echo '----' . "\n";
5433
- //echo 'Formula: ' . $formulaString;
5434
-
5435
- return $formulaString;
5436
- }
5437
-
5438
-
5439
- /**
5440
- * Fetch next token from binary formula data
5441
- *
5442
- * @param string Formula data
5443
- * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5444
- * @return array
5445
- * @throws PHPExcel_Reader_Exception
5446
- */
5447
- private function _getNextToken($formulaData, $baseCell = 'A1')
5448
- {
5449
- // offset: 0; size: 1; token id
5450
- $id = ord($formulaData[0]); // token id
5451
- $name = false; // initialize token name
5452
-
5453
- switch ($id) {
5454
- case 0x03: $name = 'tAdd'; $size = 1; $data = '+'; break;
5455
- case 0x04: $name = 'tSub'; $size = 1; $data = '-'; break;
5456
- case 0x05: $name = 'tMul'; $size = 1; $data = '*'; break;
5457
- case 0x06: $name = 'tDiv'; $size = 1; $data = '/'; break;
5458
- case 0x07: $name = 'tPower'; $size = 1; $data = '^'; break;
5459
- case 0x08: $name = 'tConcat'; $size = 1; $data = '&'; break;
5460
- case 0x09: $name = 'tLT'; $size = 1; $data = '<'; break;
5461
- case 0x0A: $name = 'tLE'; $size = 1; $data = '<='; break;
5462
- case 0x0B: $name = 'tEQ'; $size = 1; $data = '='; break;
5463
- case 0x0C: $name = 'tGE'; $size = 1; $data = '>='; break;
5464
- case 0x0D: $name = 'tGT'; $size = 1; $data = '>'; break;
5465
- case 0x0E: $name = 'tNE'; $size = 1; $data = '<>'; break;
5466
- case 0x0F: $name = 'tIsect'; $size = 1; $data = ' '; break;
5467
- case 0x10: $name = 'tList'; $size = 1; $data = ','; break;
5468
- case 0x11: $name = 'tRange'; $size = 1; $data = ':'; break;
5469
- case 0x12: $name = 'tUplus'; $size = 1; $data = '+'; break;
5470
- case 0x13: $name = 'tUminus'; $size = 1; $data = '-'; break;
5471
- case 0x14: $name = 'tPercent'; $size = 1; $data = '%'; break;
5472
- case 0x15: // parenthesis
5473
- $name = 'tParen';
5474
- $size = 1;
5475
- $data = null;
5476
- break;
5477
- case 0x16: // missing argument
5478
- $name = 'tMissArg';
5479
- $size = 1;
5480
- $data = '';
5481
- break;
5482
- case 0x17: // string
5483
- $name = 'tStr';
5484
- // offset: 1; size: var; Unicode string, 8-bit string length
5485
- $string = self::_readUnicodeStringShort(substr($formulaData, 1));
5486
- $size = 1 + $string['size'];
5487
- $data = self::_UTF8toExcelDoubleQuoted($string['value']);
5488
- break;
5489
- case 0x19: // Special attribute
5490
- // offset: 1; size: 1; attribute type flags:
5491
- switch (ord($formulaData[1])) {
5492
- case 0x01:
5493
- $name = 'tAttrVolatile';
5494
- $size = 4;
5495
- $data = null;
5496
- break;
5497
- case 0x02:
5498
- $name = 'tAttrIf';
5499
- $size = 4;
5500
- $data = null;
5501
- break;
5502
- case 0x04:
5503
- $name = 'tAttrChoose';
5504
- // offset: 2; size: 2; number of choices in the CHOOSE function ($nc, number of parameters decreased by 1)
5505
- $nc = self::_GetInt2d($formulaData, 2);
5506
- // offset: 4; size: 2 * $nc
5507
- // offset: 4 + 2 * $nc; size: 2
5508
- $size = 2 * $nc + 6;
5509
- $data = null;
5510
- break;
5511
- case 0x08:
5512
- $name = 'tAttrSkip';
5513
- $size = 4;
5514
- $data = null;
5515
- break;
5516
- case 0x10:
5517
- $name = 'tAttrSum';
5518
- $size = 4;
5519
- $data = null;
5520
- break;
5521
- case 0x40:
5522
- case 0x41:
5523
- $name = 'tAttrSpace';
5524
- $size = 4;
5525
- // offset: 2; size: 2; space type and position
5526
- switch (ord($formulaData[2])) {
5527
- case 0x00:
5528
- $spacetype = 'type0';
5529
- break;
5530
- case 0x01:
5531
- $spacetype = 'type1';
5532
- break;
5533
- case 0x02:
5534
- $spacetype = 'type2';
5535
- break;
5536
- case 0x03:
5537
- $spacetype = 'type3';
5538
- break;
5539
- case 0x04:
5540
- $spacetype = 'type4';
5541
- break;
5542
- case 0x05:
5543
- $spacetype = 'type5';
5544
- break;
5545
- default:
5546
- throw new PHPExcel_Reader_Exception('Unrecognized space type in tAttrSpace token');
5547
- break;
5548
- }
5549
- // offset: 3; size: 1; number of inserted spaces/carriage returns
5550
- $spacecount = ord($formulaData[3]);
5551
-
5552
- $data = array('spacetype' => $spacetype, 'spacecount' => $spacecount);
5553
- break;
5554
- default:
5555
- throw new PHPExcel_Reader_Exception('Unrecognized attribute flag in tAttr token');
5556
- break;
5557
- }
5558
- break;
5559
- case 0x1C: // error code
5560
- // offset: 1; size: 1; error code
5561
- $name = 'tErr';
5562
- $size = 2;
5563
- $data = self::_mapErrorCode(ord($formulaData[1]));
5564
- break;
5565
- case 0x1D: // boolean
5566
- // offset: 1; size: 1; 0 = false, 1 = true;
5567
- $name = 'tBool';
5568
- $size = 2;
5569
- $data = ord($formulaData[1]) ? 'TRUE' : 'FALSE';
5570
- break;
5571
- case 0x1E: // integer
5572
- // offset: 1; size: 2; unsigned 16-bit integer
5573
- $name = 'tInt';
5574
- $size = 3;
5575
- $data = self::_GetInt2d($formulaData, 1);
5576
- break;
5577
- case 0x1F: // number
5578
- // offset: 1; size: 8;
5579
- $name = 'tNum';
5580
- $size = 9;
5581
- $data = self::_extractNumber(substr($formulaData, 1));
5582
- $data = str_replace(',', '.', (string)$data); // in case non-English locale
5583
- break;
5584
- case 0x20: // array constant
5585
- case 0x40:
5586
- case 0x60:
5587
- // offset: 1; size: 7; not used
5588
- $name = 'tArray';
5589
- $size = 8;
5590
- $data = null;
5591
- break;
5592
- case 0x21: // function with fixed number of arguments
5593
- case 0x41:
5594
- case 0x61:
5595
- $name = 'tFunc';
5596
- $size = 3;
5597
- // offset: 1; size: 2; index to built-in sheet function
5598
- switch (self::_GetInt2d($formulaData, 1)) {
5599
- case 2: $function = 'ISNA'; $args = 1; break;
5600
- case 3: $function = 'ISERROR'; $args = 1; break;
5601
- case 10: $function = 'NA'; $args = 0; break;
5602
- case 15: $function = 'SIN'; $args = 1; break;
5603
- case 16: $function = 'COS'; $args = 1; break;
5604
- case 17: $function = 'TAN'; $args = 1; break;
5605
- case 18: $function = 'ATAN'; $args = 1; break;
5606
- case 19: $function = 'PI'; $args = 0; break;
5607
- case 20: $function = 'SQRT'; $args = 1; break;
5608
- case 21: $function = 'EXP'; $args = 1; break;
5609
- case 22: $function = 'LN'; $args = 1; break;
5610
- case 23: $function = 'LOG10'; $args = 1; break;
5611
- case 24: $function = 'ABS'; $args = 1; break;
5612
- case 25: $function = 'INT'; $args = 1; break;
5613
- case 26: $function = 'SIGN'; $args = 1; break;
5614
- case 27: $function = 'ROUND'; $args = 2; break;
5615
- case 30: $function = 'REPT'; $args = 2; break;
5616
- case 31: $function = 'MID'; $args = 3; break;
5617
- case 32: $function = 'LEN'; $args = 1; break;
5618
- case 33: $function = 'VALUE'; $args = 1; break;
5619
- case 34: $function = 'TRUE'; $args = 0; break;
5620
- case 35: $function = 'FALSE'; $args = 0; break;
5621
- case 38: $function = 'NOT'; $args = 1; break;
5622
- case 39: $function = 'MOD'; $args = 2; break;
5623
- case 40: $function = 'DCOUNT'; $args = 3; break;
5624
- case 41: $function = 'DSUM'; $args = 3; break;
5625
- case 42: $function = 'DAVERAGE'; $args = 3; break;
5626
- case 43: $function = 'DMIN'; $args = 3; break;
5627
- case 44: $function = 'DMAX'; $args = 3; break;
5628
- case 45: $function = 'DSTDEV'; $args = 3; break;
5629
- case 48: $function = 'TEXT'; $args = 2; break;
5630
- case 61: $function = 'MIRR'; $args = 3; break;
5631
- case 63: $function = 'RAND'; $args = 0; break;
5632
- case 65: $function = 'DATE'; $args = 3; break;
5633
- case 66: $function = 'TIME'; $args = 3; break;
5634
- case 67: $function = 'DAY'; $args = 1; break;
5635
- case 68: $function = 'MONTH'; $args = 1; break;
5636
- case 69: $function = 'YEAR'; $args = 1; break;
5637
- case 71: $function = 'HOUR'; $args = 1; break;
5638
- case 72: $function = 'MINUTE'; $args = 1; break;
5639
- case 73: $function = 'SECOND'; $args = 1; break;
5640
- case 74: $function = 'NOW'; $args = 0; break;
5641
- case 75: $function = 'AREAS'; $args = 1; break;
5642
- case 76: $function = 'ROWS'; $args = 1; break;
5643
- case 77: $function = 'COLUMNS'; $args = 1; break;
5644
- case 83: $function = 'TRANSPOSE'; $args = 1; break;
5645
- case 86: $function = 'TYPE'; $args = 1; break;
5646
- case 97: $function = 'ATAN2'; $args = 2; break;
5647
- case 98: $function = 'ASIN'; $args = 1; break;
5648
- case 99: $function = 'ACOS'; $args = 1; break;
5649
- case 105: $function = 'ISREF'; $args = 1; break;
5650
- case 111: $function = 'CHAR'; $args = 1; break;
5651
- case 112: $function = 'LOWER'; $args = 1; break;
5652
- case 113: $function = 'UPPER'; $args = 1; break;
5653
- case 114: $function = 'PROPER'; $args = 1; break;
5654
- case 117: $function = 'EXACT'; $args = 2; break;
5655
- case 118: $function = 'TRIM'; $args = 1; break;
5656
- case 119: $function = 'REPLACE'; $args = 4; break;
5657
- case 121: $function = 'CODE'; $args = 1; break;
5658
- case 126: $function = 'ISERR'; $args = 1; break;
5659
- case 127: $function = 'ISTEXT'; $args = 1; break;
5660
- case 128: $function = 'ISNUMBER'; $args = 1; break;
5661
- case 129: $function = 'ISBLANK'; $args = 1; break;
5662
- case 130: $function = 'T'; $args = 1; break;
5663
- case 131: $function = 'N'; $args = 1; break;
5664
- case 140: $function = 'DATEVALUE'; $args = 1; break;
5665
- case 141: $function = 'TIMEVALUE'; $args = 1; break;
5666
- case 142: $function = 'SLN'; $args = 3; break;
5667
- case 143: $function = 'SYD'; $args = 4; break;
5668
- case 162: $function = 'CLEAN'; $args = 1; break;
5669
- case 163: $function = 'MDETERM'; $args = 1; break;
5670
- case 164: $function = 'MINVERSE'; $args = 1; break;
5671
- case 165: $function = 'MMULT'; $args = 2; break;
5672
- case 184: $function = 'FACT'; $args = 1; break;
5673
- case 189: $function = 'DPRODUCT'; $args = 3; break;
5674
- case 190: $function = 'ISNONTEXT'; $args = 1; break;
5675
- case 195: $function = 'DSTDEVP'; $args = 3; break;
5676
- case 196: $function = 'DVARP'; $args = 3; break;
5677
- case 198: $function = 'ISLOGICAL'; $args = 1; break;
5678
- case 199: $function = 'DCOUNTA'; $args = 3; break;
5679
- case 207: $function = 'REPLACEB'; $args = 4; break;
5680
- case 210: $function = 'MIDB'; $args = 3; break;
5681
- case 211: $function = 'LENB'; $args = 1; break;
5682
- case 212: $function = 'ROUNDUP'; $args = 2; break;
5683
- case 213: $function = 'ROUNDDOWN'; $args = 2; break;
5684
- case 214: $function = 'ASC'; $args = 1; break;
5685
- case 215: $function = 'DBCS'; $args = 1; break;
5686
- case 221: $function = 'TODAY'; $args = 0; break;
5687
- case 229: $function = 'SINH'; $args = 1; break;
5688
- case 230: $function = 'COSH'; $args = 1; break;
5689
- case 231: $function = 'TANH'; $args = 1; break;
5690
- case 232: $function = 'ASINH'; $args = 1; break;
5691
- case 233: $function = 'ACOSH'; $args = 1; break;
5692
- case 234: $function = 'ATANH'; $args = 1; break;
5693
- case 235: $function = 'DGET'; $args = 3; break;
5694
- case 244: $function = 'INFO'; $args = 1; break;
5695
- case 252: $function = 'FREQUENCY'; $args = 2; break;
5696
- case 261: $function = 'ERROR.TYPE'; $args = 1; break;
5697
- case 271: $function = 'GAMMALN'; $args = 1; break;
5698
- case 273: $function = 'BINOMDIST'; $args = 4; break;
5699
- case 274: $function = 'CHIDIST'; $args = 2; break;
5700
- case 275: $function = 'CHIINV'; $args = 2; break;
5701
- case 276: $function = 'COMBIN'; $args = 2; break;
5702
- case 277: $function = 'CONFIDENCE'; $args = 3; break;
5703
- case 278: $function = 'CRITBINOM'; $args = 3; break;
5704
- case 279: $function = 'EVEN'; $args = 1; break;
5705
- case 280: $function = 'EXPONDIST'; $args = 3; break;
5706
- case 281: $function = 'FDIST'; $args = 3; break;
5707
- case 282: $function = 'FINV'; $args = 3; break;
5708
- case 283: $function = 'FISHER'; $args = 1; break;
5709
- case 284: $function = 'FISHERINV'; $args = 1; break;
5710
- case 285: $function = 'FLOOR'; $args = 2; break;
5711
- case 286: $function = 'GAMMADIST'; $args = 4; break;
5712
- case 287: $function = 'GAMMAINV'; $args = 3; break;
5713
- case 288: $function = 'CEILING'; $args = 2; break;
5714
- case 289: $function = 'HYPGEOMDIST'; $args = 4; break;
5715
- case 290: $function = 'LOGNORMDIST'; $args = 3; break;
5716
- case 291: $function = 'LOGINV'; $args = 3; break;
5717
- case 292: $function = 'NEGBINOMDIST'; $args = 3; break;
5718
- case 293: $function = 'NORMDIST'; $args = 4; break;
5719
- case 294: $function = 'NORMSDIST'; $args = 1; break;
5720
- case 295: $function = 'NORMINV'; $args = 3; break;
5721
- case 296: $function = 'NORMSINV'; $args = 1; break;
5722
- case 297: $function = 'STANDARDIZE'; $args = 3; break;
5723
- case 298: $function = 'ODD'; $args = 1; break;
5724
- case 299: $function = 'PERMUT'; $args = 2; break;
5725
- case 300: $function = 'POISSON'; $args = 3; break;
5726
- case 301: $function = 'TDIST'; $args = 3; break;
5727
- case 302: $function = 'WEIBULL'; $args = 4; break;
5728
- case 303: $function = 'SUMXMY2'; $args = 2; break;
5729
- case 304: $function = 'SUMX2MY2'; $args = 2; break;
5730
- case 305: $function = 'SUMX2PY2'; $args = 2; break;
5731
- case 306: $function = 'CHITEST'; $args = 2; break;
5732
- case 307: $function = 'CORREL'; $args = 2; break;
5733
- case 308: $function = 'COVAR'; $args = 2; break;
5734
- case 309: $function = 'FORECAST'; $args = 3; break;
5735
- case 310: $function = 'FTEST'; $args = 2; break;
5736
- case 311: $function = 'INTERCEPT'; $args = 2; break;
5737
- case 312: $function = 'PEARSON'; $args = 2; break;
5738
- case 313: $function = 'RSQ'; $args = 2; break;
5739
- case 314: $function = 'STEYX'; $args = 2; break;
5740
- case 315: $function = 'SLOPE'; $args = 2; break;
5741
- case 316: $function = 'TTEST'; $args = 4; break;
5742
- case 325: $function = 'LARGE'; $args = 2; break;
5743
- case 326: $function = 'SMALL'; $args = 2; break;
5744
- case 327: $function = 'QUARTILE'; $args = 2; break;
5745
- case 328: $function = 'PERCENTILE'; $args = 2; break;
5746
- case 331: $function = 'TRIMMEAN'; $args = 2; break;
5747
- case 332: $function = 'TINV'; $args = 2; break;
5748
- case 337: $function = 'POWER'; $args = 2; break;
5749
- case 342: $function = 'RADIANS'; $args = 1; break;
5750
- case 343: $function = 'DEGREES'; $args = 1; break;
5751
- case 346: $function = 'COUNTIF'; $args = 2; break;
5752
- case 347: $function = 'COUNTBLANK'; $args = 1; break;
5753
- case 350: $function = 'ISPMT'; $args = 4; break;
5754
- case 351: $function = 'DATEDIF'; $args = 3; break;
5755
- case 352: $function = 'DATESTRING'; $args = 1; break;
5756
- case 353: $function = 'NUMBERSTRING'; $args = 2; break;
5757
- case 360: $function = 'PHONETIC'; $args = 1; break;
5758
- case 368: $function = 'BAHTTEXT'; $args = 1; break;
5759
- default:
5760
- throw new PHPExcel_Reader_Exception('Unrecognized function in formula');
5761
- break;
5762
- }
5763
- $data = array('function' => $function, 'args' => $args);
5764
- break;
5765
- case 0x22: // function with variable number of arguments
5766
- case 0x42:
5767
- case 0x62:
5768
- $name = 'tFuncV';
5769
- $size = 4;
5770
- // offset: 1; size: 1; number of arguments
5771
- $args = ord($formulaData[1]);
5772
- // offset: 2: size: 2; index to built-in sheet function
5773
- $index = self::_GetInt2d($formulaData, 2);
5774
- switch ($index) {
5775
- case 0: $function = 'COUNT'; break;
5776
- case 1: $function = 'IF'; break;
5777
- case 4: $function = 'SUM'; break;
5778
- case 5: $function = 'AVERAGE'; break;
5779
- case 6: $function = 'MIN'; break;
5780
- case 7: $function = 'MAX'; break;
5781
- case 8: $function = 'ROW'; break;
5782
- case 9: $function = 'COLUMN'; break;
5783
- case 11: $function = 'NPV'; break;
5784
- case 12: $function = 'STDEV'; break;
5785
- case 13: $function = 'DOLLAR'; break;
5786
- case 14: $function = 'FIXED'; break;
5787
- case 28: $function = 'LOOKUP'; break;
5788
- case 29: $function = 'INDEX'; break;
5789
- case 36: $function = 'AND'; break;
5790
- case 37: $function = 'OR'; break;
5791
- case 46: $function = 'VAR'; break;
5792
- case 49: $function = 'LINEST'; break;
5793
- case 50: $function = 'TREND'; break;
5794
- case 51: $function = 'LOGEST'; break;
5795
- case 52: $function = 'GROWTH'; break;
5796
- case 56: $function = 'PV'; break;
5797
- case 57: $function = 'FV'; break;
5798
- case 58: $function = 'NPER'; break;
5799
- case 59: $function = 'PMT'; break;
5800
- case 60: $function = 'RATE'; break;
5801
- case 62: $function = 'IRR'; break;
5802
- case 64: $function = 'MATCH'; break;
5803
- case 70: $function = 'WEEKDAY'; break;
5804
- case 78: $function = 'OFFSET'; break;
5805
- case 82: $function = 'SEARCH'; break;
5806
- case 100: $function = 'CHOOSE'; break;
5807
- case 101: $function = 'HLOOKUP'; break;
5808
- case 102: $function = 'VLOOKUP'; break;
5809
- case 109: $function = 'LOG'; break;
5810
- case 115: $function = 'LEFT'; break;
5811
- case 116: $function = 'RIGHT'; break;
5812
- case 120: $function = 'SUBSTITUTE'; break;
5813
- case 124: $function = 'FIND'; break;
5814
- case 125: $function = 'CELL'; break;
5815
- case 144: $function = 'DDB'; break;
5816
- case 148: $function = 'INDIRECT'; break;
5817
- case 167: $function = 'IPMT'; break;
5818
- case 168: $function = 'PPMT'; break;
5819
- case 169: $function = 'COUNTA'; break;
5820
- case 183: $function = 'PRODUCT'; break;
5821
- case 193: $function = 'STDEVP'; break;
5822
- case 194: $function = 'VARP'; break;
5823
- case 197: $function = 'TRUNC'; break;
5824
- case 204: $function = 'USDOLLAR'; break;
5825
- case 205: $function = 'FINDB'; break;
5826
- case 206: $function = 'SEARCHB'; break;
5827
- case 208: $function = 'LEFTB'; break;
5828
- case 209: $function = 'RIGHTB'; break;
5829
- case 216: $function = 'RANK'; break;
5830
- case 219: $function = 'ADDRESS'; break;
5831
- case 220: $function = 'DAYS360'; break;
5832
- case 222: $function = 'VDB'; break;
5833
- case 227: $function = 'MEDIAN'; break;
5834
- case 228: $function = 'SUMPRODUCT'; break;
5835
- case 247: $function = 'DB'; break;
5836
- case 255: $function = ''; break;
5837
- case 269: $function = 'AVEDEV'; break;
5838
- case 270: $function = 'BETADIST'; break;
5839
- case 272: $function = 'BETAINV'; break;
5840
- case 317: $function = 'PROB'; break;
5841
- case 318: $function = 'DEVSQ'; break;
5842
- case 319: $function = 'GEOMEAN'; break;
5843
- case 320: $function = 'HARMEAN'; break;
5844
- case 321: $function = 'SUMSQ'; break;
5845
- case 322: $function = 'KURT'; break;
5846
- case 323: $function = 'SKEW'; break;
5847
- case 324: $function = 'ZTEST'; break;
5848
- case 329: $function = 'PERCENTRANK'; break;
5849
- case 330: $function = 'MODE'; break;
5850
- case 336: $function = 'CONCATENATE'; break;
5851
- case 344: $function = 'SUBTOTAL'; break;
5852
- case 345: $function = 'SUMIF'; break;
5853
- case 354: $function = 'ROMAN'; break;
5854
- case 358: $function = 'GETPIVOTDATA'; break;
5855
- case 359: $function = 'HYPERLINK'; break;
5856
- case 361: $function = 'AVERAGEA'; break;
5857
- case 362: $function = 'MAXA'; break;
5858
- case 363: $function = 'MINA'; break;
5859
- case 364: $function = 'STDEVPA'; break;
5860
- case 365: $function = 'VARPA'; break;
5861
- case 366: $function = 'STDEVA'; break;
5862
- case 367: $function = 'VARA'; break;
5863
- default:
5864
- throw new PHPExcel_Reader_Exception('Unrecognized function in formula');
5865
- break;
5866
- }
5867
- $data = array('function' => $function, 'args' => $args);
5868
- break;
5869
- case 0x23: // index to defined name
5870
- case 0x43:
5871
- case 0x63:
5872
- $name = 'tName';
5873
- $size = 5;
5874
- // offset: 1; size: 2; one-based index to definedname record
5875
- $definedNameIndex = self::_GetInt2d($formulaData, 1) - 1;
5876
- // offset: 2; size: 2; not used
5877
- $data = $this->_definedname[$definedNameIndex]['name'];
5878
- break;
5879
- case 0x24: // single cell reference e.g. A5
5880
- case 0x44:
5881
- case 0x64:
5882
- $name = 'tRef';
5883
- $size = 5;
5884
- $data = $this->_readBIFF8CellAddress(substr($formulaData, 1, 4));
5885
- break;
5886
- case 0x25: // cell range reference to cells in the same sheet (2d)
5887
- case 0x45:
5888
- case 0x65:
5889
- $name = 'tArea';
5890
- $size = 9;
5891
- $data = $this->_readBIFF8CellRangeAddress(substr($formulaData, 1, 8));
5892
- break;
5893
- case 0x26: // Constant reference sub-expression
5894
- case 0x46:
5895
- case 0x66:
5896
- $name = 'tMemArea';
5897
- // offset: 1; size: 4; not used
5898
- // offset: 5; size: 2; size of the following subexpression
5899
- $subSize = self::_GetInt2d($formulaData, 5);
5900
- $size = 7 + $subSize;
5901
- $data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
5902
- break;
5903
- case 0x27: // Deleted constant reference sub-expression
5904
- case 0x47:
5905
- case 0x67:
5906
- $name = 'tMemErr';
5907
- // offset: 1; size: 4; not used
5908
- // offset: 5; size: 2; size of the following subexpression
5909
- $subSize = self::_GetInt2d($formulaData, 5);
5910
- $size = 7 + $subSize;
5911
- $data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
5912
- break;
5913
- case 0x29: // Variable reference sub-expression
5914
- case 0x49:
5915
- case 0x69:
5916
- $name = 'tMemFunc';
5917
- // offset: 1; size: 2; size of the following sub-expression
5918
- $subSize = self::_GetInt2d($formulaData, 1);
5919
- $size = 3 + $subSize;
5920
- $data = $this->_getFormulaFromData(substr($formulaData, 3, $subSize));
5921
- break;
5922
-
5923
- case 0x2C: // Relative 2d cell reference reference, used in shared formulas and some other places
5924
- case 0x4C:
5925
- case 0x6C:
5926
- $name = 'tRefN';
5927
- $size = 5;
5928
- $data = $this->_readBIFF8CellAddressB(substr($formulaData, 1, 4), $baseCell);
5929
- break;
5930
-
5931
- case 0x2D: // Relative 2d range reference
5932
- case 0x4D:
5933
- case 0x6D:
5934
- $name = 'tAreaN';
5935
- $size = 9;
5936
- $data = $this->_readBIFF8CellRangeAddressB(substr($formulaData, 1, 8), $baseCell);
5937
- break;
5938
-
5939
- case 0x39: // External name
5940
- case 0x59:
5941
- case 0x79:
5942
- $name = 'tNameX';
5943
- $size = 7;
5944
- // offset: 1; size: 2; index to REF entry in EXTERNSHEET record
5945
- // offset: 3; size: 2; one-based index to DEFINEDNAME or EXTERNNAME record
5946
- $index = self::_GetInt2d($formulaData, 3);
5947
- // assume index is to EXTERNNAME record
5948
- $data = $this->_externalNames[$index - 1]['name'];
5949
- // offset: 5; size: 2; not used
5950
- break;
5951
-
5952
- case 0x3A: // 3d reference to cell
5953
- case 0x5A:
5954
- case 0x7A:
5955
- $name = 'tRef3d';
5956
- $size = 7;
5957
-
5958
- try {
5959
- // offset: 1; size: 2; index to REF entry
5960
- $sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
5961
- // offset: 3; size: 4; cell address
5962
- $cellAddress = $this->_readBIFF8CellAddress(substr($formulaData, 3, 4));
5963
-
5964
- $data = "$sheetRange!$cellAddress";
5965
- } catch (PHPExcel_Exception $e) {
5966
- // deleted sheet reference
5967
- $data = '#REF!';
5968
- }
5969
-
5970
- break;
5971
- case 0x3B: // 3d reference to cell range
5972
- case 0x5B:
5973
- case 0x7B:
5974
- $name = 'tArea3d';
5975
- $size = 11;
5976
-
5977
- try {
5978
- // offset: 1; size: 2; index to REF entry
5979
- $sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
5980
- // offset: 3; size: 8; cell address
5981
- $cellRangeAddress = $this->_readBIFF8CellRangeAddress(substr($formulaData, 3, 8));
5982
-
5983
- $data = "$sheetRange!$cellRangeAddress";
5984
- } catch (PHPExcel_Exception $e) {
5985
- // deleted sheet reference
5986
- $data = '#REF!';
5987
- }
5988
-
5989
- break;
5990
- // Unknown cases // don't know how to deal with
5991
- default:
5992
- throw new PHPExcel_Reader_Exception('Unrecognized token ' . sprintf('%02X', $id) . ' in formula');
5993
- break;
5994
- }
5995
-
5996
- return array(
5997
- 'id' => $id,
5998
- 'name' => $name,
5999
- 'size' => $size,
6000
- 'data' => $data,
6001
- );
6002
- }
6003
-
6004
-
6005
- /**
6006
- * Reads a cell address in BIFF8 e.g. 'A2' or '$A$2'
6007
- * section 3.3.4
6008
- *
6009
- * @param string $cellAddressStructure
6010
- * @return string
6011
- */
6012
- private function _readBIFF8CellAddress($cellAddressStructure)
6013
- {
6014
- // offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
6015
- $row = self::_GetInt2d($cellAddressStructure, 0) + 1;
6016
-
6017
- // offset: 2; size: 2; index to column or column offset + relative flags
6018
-
6019
- // bit: 7-0; mask 0x00FF; column index
6020
- $column = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($cellAddressStructure, 2));
6021
-
6022
- // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6023
- if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) {
6024
- $column = '$' . $column;
6025
- }
6026
- // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6027
- if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) {
6028
- $row = '$' . $row;
6029
- }
6030
-
6031
- return $column . $row;
6032
- }
6033
-
6034
-
6035
- /**
6036
- * Reads a cell address in BIFF8 for shared formulas. Uses positive and negative values for row and column
6037
- * to indicate offsets from a base cell
6038
- * section 3.3.4
6039
- *
6040
- * @param string $cellAddressStructure
6041
- * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
6042
- * @return string
6043
- */
6044
- private function _readBIFF8CellAddressB($cellAddressStructure, $baseCell = 'A1')
6045
- {
6046
- list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
6047
- $baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
6048
-
6049
- // offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
6050
- $rowIndex = self::_GetInt2d($cellAddressStructure, 0);
6051
- $row = self::_GetInt2d($cellAddressStructure, 0) + 1;
6052
-
6053
- // offset: 2; size: 2; index to column or column offset + relative flags
6054
-
6055
- // bit: 7-0; mask 0x00FF; column index
6056
- $colIndex = 0x00FF & self::_GetInt2d($cellAddressStructure, 2);
6057
-
6058
- // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6059
- if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) {
6060
- $column = PHPExcel_Cell::stringFromColumnIndex($colIndex);
6061
- $column = '$' . $column;
6062
- } else {
6063
- $colIndex = ($colIndex <= 127) ? $colIndex : $colIndex - 256;
6064
- $column = PHPExcel_Cell::stringFromColumnIndex($baseCol + $colIndex);
6065
- }
6066
-
6067
- // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6068
- if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) {
6069
- $row = '$' . $row;
6070
- } else {
6071
- $rowIndex = ($rowIndex <= 32767) ? $rowIndex : $rowIndex - 65536;
6072
- $row = $baseRow + $rowIndex;
6073
- }
6074
-
6075
- return $column . $row;
6076
- }
6077
-
6078
-
6079
- /**
6080
- * Reads a cell range address in BIFF5 e.g. 'A2:B6' or 'A1'
6081
- * always fixed range
6082
- * section 2.5.14
6083
- *
6084
- * @param string $subData
6085
- * @return string
6086
- * @throws PHPExcel_Reader_Exception
6087
- */
6088
- private function _readBIFF5CellRangeAddressFixed($subData)
6089
- {
6090
- // offset: 0; size: 2; index to first row
6091
- $fr = self::_GetInt2d($subData, 0) + 1;
6092
-
6093
- // offset: 2; size: 2; index to last row
6094
- $lr = self::_GetInt2d($subData, 2) + 1;
6095
-
6096
- // offset: 4; size: 1; index to first column
6097
- $fc = ord($subData{4});
6098
-
6099
- // offset: 5; size: 1; index to last column
6100
- $lc = ord($subData{5});
6101
-
6102
- // check values
6103
- if ($fr > $lr || $fc > $lc) {
6104
- throw new PHPExcel_Reader_Exception('Not a cell range address');
6105
- }
6106
-
6107
- // column index to letter
6108
- $fc = PHPExcel_Cell::stringFromColumnIndex($fc);
6109
- $lc = PHPExcel_Cell::stringFromColumnIndex($lc);
6110
-
6111
- if ($fr == $lr and $fc == $lc) {
6112
- return "$fc$fr";
6113
- }
6114
- return "$fc$fr:$lc$lr";
6115
- }
6116
-
6117
-
6118
- /**
6119
- * Reads a cell range address in BIFF8 e.g. 'A2:B6' or 'A1'
6120
- * always fixed range
6121
- * section 2.5.14
6122
- *
6123
- * @param string $subData
6124
- * @return string
6125
- * @throws PHPExcel_Reader_Exception
6126
- */
6127
- private function _readBIFF8CellRangeAddressFixed($subData)
6128
- {
6129
- // offset: 0; size: 2; index to first row
6130
- $fr = self::_GetInt2d($subData, 0) + 1;
6131
-
6132
- // offset: 2; size: 2; index to last row
6133
- $lr = self::_GetInt2d($subData, 2) + 1;
6134
-
6135
- // offset: 4; size: 2; index to first column
6136
- $fc = self::_GetInt2d($subData, 4);
6137
-
6138
- // offset: 6; size: 2; index to last column
6139
- $lc = self::_GetInt2d($subData, 6);
6140
-
6141
- // check values
6142
- if ($fr > $lr || $fc > $lc) {
6143
- throw new PHPExcel_Reader_Exception('Not a cell range address');
6144
- }
6145
-
6146
- // column index to letter
6147
- $fc = PHPExcel_Cell::stringFromColumnIndex($fc);
6148
- $lc = PHPExcel_Cell::stringFromColumnIndex($lc);
6149
-
6150
- if ($fr == $lr and $fc == $lc) {
6151
- return "$fc$fr";
6152
- }
6153
- return "$fc$fr:$lc$lr";
6154
- }
6155
-
6156
-
6157
- /**
6158
- * Reads a cell range address in BIFF8 e.g. 'A2:B6' or '$A$2:$B$6'
6159
- * there are flags indicating whether column/row index is relative
6160
- * section 3.3.4
6161
- *
6162
- * @param string $subData
6163
- * @return string
6164
- */
6165
- private function _readBIFF8CellRangeAddress($subData)
6166
- {
6167
- // todo: if cell range is just a single cell, should this funciton
6168
- // not just return e.g. 'A1' and not 'A1:A1' ?
6169
-
6170
- // offset: 0; size: 2; index to first row (0... 65535) (or offset (-32768... 32767))
6171
- $fr = self::_GetInt2d($subData, 0) + 1;
6172
-
6173
- // offset: 2; size: 2; index to last row (0... 65535) (or offset (-32768... 32767))
6174
- $lr = self::_GetInt2d($subData, 2) + 1;
6175
-
6176
- // offset: 4; size: 2; index to first column or column offset + relative flags
6177
-
6178
- // bit: 7-0; mask 0x00FF; column index
6179
- $fc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 4));
6180
-
6181
- // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6182
- if (!(0x4000 & self::_GetInt2d($subData, 4))) {
6183
- $fc = '$' . $fc;
6184
- }
6185
-
6186
- // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6187
- if (!(0x8000 & self::_GetInt2d($subData, 4))) {
6188
- $fr = '$' . $fr;
6189
- }
6190
-
6191
- // offset: 6; size: 2; index to last column or column offset + relative flags
6192
-
6193
- // bit: 7-0; mask 0x00FF; column index
6194
- $lc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 6));
6195
-
6196
- // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6197
- if (!(0x4000 & self::_GetInt2d($subData, 6))) {
6198
- $lc = '$' . $lc;
6199
- }
6200
-
6201
- // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6202
- if (!(0x8000 & self::_GetInt2d($subData, 6))) {
6203
- $lr = '$' . $lr;
6204
- }
6205
-
6206
- return "$fc$fr:$lc$lr";
6207
- }
6208
-
6209
-
6210
- /**
6211
- * Reads a cell range address in BIFF8 for shared formulas. Uses positive and negative values for row and column
6212
- * to indicate offsets from a base cell
6213
- * section 3.3.4
6214
- *
6215
- * @param string $subData
6216
- * @param string $baseCell Base cell
6217
- * @return string Cell range address
6218
- */
6219
- private function _readBIFF8CellRangeAddressB($subData, $baseCell = 'A1')
6220
- {
6221
- list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
6222
- $baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
6223
-
6224
- // TODO: if cell range is just a single cell, should this funciton
6225
- // not just return e.g. 'A1' and not 'A1:A1' ?
6226
-
6227
- // offset: 0; size: 2; first row
6228
- $frIndex = self::_GetInt2d($subData, 0); // adjust below
6229
-
6230
- // offset: 2; size: 2; relative index to first row (0... 65535) should be treated as offset (-32768... 32767)
6231
- $lrIndex = self::_GetInt2d($subData, 2); // adjust below
6232
-
6233
- // offset: 4; size: 2; first column with relative/absolute flags
6234
-
6235
- // bit: 7-0; mask 0x00FF; column index
6236
- $fcIndex = 0x00FF & self::_GetInt2d($subData, 4);
6237
-
6238
- // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6239
- if (!(0x4000 & self::_GetInt2d($subData, 4))) {
6240
- // absolute column index
6241
- $fc = PHPExcel_Cell::stringFromColumnIndex($fcIndex);
6242
- $fc = '$' . $fc;
6243
- } else {
6244
- // column offset
6245
- $fcIndex = ($fcIndex <= 127) ? $fcIndex : $fcIndex - 256;
6246
- $fc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $fcIndex);
6247
- }
6248
-
6249
- // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6250
- if (!(0x8000 & self::_GetInt2d($subData, 4))) {
6251
- // absolute row index
6252
- $fr = $frIndex + 1;
6253
- $fr = '$' . $fr;
6254
- } else {
6255
- // row offset
6256
- $frIndex = ($frIndex <= 32767) ? $frIndex : $frIndex - 65536;
6257
- $fr = $baseRow + $frIndex;
6258
- }
6259
-
6260
- // offset: 6; size: 2; last column with relative/absolute flags
6261
-
6262
- // bit: 7-0; mask 0x00FF; column index
6263
- $lcIndex = 0x00FF & self::_GetInt2d($subData, 6);
6264
- $lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
6265
- $lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
6266
-
6267
- // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6268
- if (!(0x4000 & self::_GetInt2d($subData, 6))) {
6269
- // absolute column index
6270
- $lc = PHPExcel_Cell::stringFromColumnIndex($lcIndex);
6271
- $lc = '$' . $lc;
6272
- } else {
6273
- // column offset
6274
- $lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
6275
- $lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
6276
- }
6277
-
6278
- // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6279
- if (!(0x8000 & self::_GetInt2d($subData, 6))) {
6280
- // absolute row index
6281
- $lr = $lrIndex + 1;
6282
- $lr = '$' . $lr;
6283
- } else {
6284
- // row offset
6285
- $lrIndex = ($lrIndex <= 32767) ? $lrIndex : $lrIndex - 65536;
6286
- $lr = $baseRow + $lrIndex;
6287
- }
6288
-
6289
- return "$fc$fr:$lc$lr";
6290
- }
6291
-
6292
-
6293
- /**
6294
- * Read BIFF8 cell range address list
6295
- * section 2.5.15
6296
- *
6297
- * @param string $subData
6298
- * @return array
6299
- */
6300
- private function _readBIFF8CellRangeAddressList($subData)
6301
- {
6302
- $cellRangeAddresses = array();
6303
-
6304
- // offset: 0; size: 2; number of the following cell range addresses
6305
- $nm = self::_GetInt2d($subData, 0);
6306
-
6307
- $offset = 2;
6308
- // offset: 2; size: 8 * $nm; list of $nm (fixed) cell range addresses
6309
- for ($i = 0; $i < $nm; ++$i) {
6310
- $cellRangeAddresses[] = $this->_readBIFF8CellRangeAddressFixed(substr($subData, $offset, 8));
6311
- $offset += 8;
6312
- }
6313
-
6314
- return array(
6315
- 'size' => 2 + 8 * $nm,
6316
- 'cellRangeAddresses' => $cellRangeAddresses,
6317
- );
6318
- }
6319
-
6320
-
6321
- /**
6322
- * Read BIFF5 cell range address list
6323
- * section 2.5.15
6324
- *
6325
- * @param string $subData
6326
- * @return array
6327
- */
6328
- private function _readBIFF5CellRangeAddressList($subData)
6329
- {
6330
- $cellRangeAddresses = array();
6331
-
6332
- // offset: 0; size: 2; number of the following cell range addresses
6333
- $nm = self::_GetInt2d($subData, 0);
6334
-
6335
- $offset = 2;
6336
- // offset: 2; size: 6 * $nm; list of $nm (fixed) cell range addresses
6337
- for ($i = 0; $i < $nm; ++$i) {
6338
- $cellRangeAddresses[] = $this->_readBIFF5CellRangeAddressFixed(substr($subData, $offset, 6));
6339
- $offset += 6;
6340
- }
6341
-
6342
- return array(
6343
- 'size' => 2 + 6 * $nm,
6344
- 'cellRangeAddresses' => $cellRangeAddresses,
6345
- );
6346
- }
6347
-
6348
-
6349
- /**
6350
- * Get a sheet range like Sheet1:Sheet3 from REF index
6351
- * Note: If there is only one sheet in the range, one gets e.g Sheet1
6352
- * It can also happen that the REF structure uses the -1 (FFFF) code to indicate deleted sheets,
6353
- * in which case an PHPExcel_Reader_Exception is thrown
6354
- *
6355
- * @param int $index
6356
- * @return string|false
6357
- * @throws PHPExcel_Reader_Exception
6358
- */
6359
- private function _readSheetRangeByRefIndex($index)
6360
- {
6361
- if (isset($this->_ref[$index])) {
6362
-
6363
- $type = $this->_externalBooks[$this->_ref[$index]['externalBookIndex']]['type'];
6364
-
6365
- switch ($type) {
6366
- case 'internal':
6367
- // check if we have a deleted 3d reference
6368
- if ($this->_ref[$index]['firstSheetIndex'] == 0xFFFF or $this->_ref[$index]['lastSheetIndex'] == 0xFFFF) {
6369
- throw new PHPExcel_Reader_Exception('Deleted sheet reference');
6370
- }
6371
-
6372
- // we have normal sheet range (collapsed or uncollapsed)
6373
- $firstSheetName = $this->_sheets[$this->_ref[$index]['firstSheetIndex']]['name'];
6374
- $lastSheetName = $this->_sheets[$this->_ref[$index]['lastSheetIndex']]['name'];
6375
-
6376
- if ($firstSheetName == $lastSheetName) {
6377
- // collapsed sheet range
6378
- $sheetRange = $firstSheetName;
6379
- } else {
6380
- $sheetRange = "$firstSheetName:$lastSheetName";
6381
- }
6382
-
6383
- // escape the single-quotes
6384
- $sheetRange = str_replace("'", "''", $sheetRange);
6385
-
6386
- // if there are special characters, we need to enclose the range in single-quotes
6387
- // todo: check if we have identified the whole set of special characters
6388
- // it seems that the following characters are not accepted for sheet names
6389
- // and we may assume that they are not present: []*/:\?
6390
- if (preg_match("/[ !\"@#£$%&{()}<>=+'|^,;-]/", $sheetRange)) {
6391
- $sheetRange = "'$sheetRange'";
6392
- }
6393
-
6394
- return $sheetRange;
6395
- break;
6396
-
6397
- default:
6398
- // TODO: external sheet support
6399
- throw new PHPExcel_Reader_Exception('Excel5 reader only supports internal sheets in fomulas');
6400
- break;
6401
- }
6402
- }
6403
- return false;
6404
- }
6405
-
6406
-
6407
- /**
6408
- * read BIFF8 constant value array from array data
6409
- * returns e.g. array('value' => '{1,2;3,4}', 'size' => 40}
6410
- * section 2.5.8
6411
- *
6412
- * @param string $arrayData
6413
- * @return array
6414
- */
6415
- private static function _readBIFF8ConstantArray($arrayData)
6416
- {
6417
- // offset: 0; size: 1; number of columns decreased by 1
6418
- $nc = ord($arrayData[0]);
6419
-
6420
- // offset: 1; size: 2; number of rows decreased by 1
6421
- $nr = self::_GetInt2d($arrayData, 1);
6422
- $size = 3; // initialize
6423
- $arrayData = substr($arrayData, 3);
6424
-
6425
- // offset: 3; size: var; list of ($nc + 1) * ($nr + 1) constant values
6426
- $matrixChunks = array();
6427
- for ($r = 1; $r <= $nr + 1; ++$r) {
6428
- $items = array();
6429
- for ($c = 1; $c <= $nc + 1; ++$c) {
6430
- $constant = self::_readBIFF8Constant($arrayData);
6431
- $items[] = $constant['value'];
6432
- $arrayData = substr($arrayData, $constant['size']);
6433
- $size += $constant['size'];
6434
- }
6435
- $matrixChunks[] = implode(',', $items); // looks like e.g. '1,"hello"'
6436
- }
6437
- $matrix = '{' . implode(';', $matrixChunks) . '}';
6438
-
6439
- return array(
6440
- 'value' => $matrix,
6441
- 'size' => $size,
6442
- );
6443
- }
6444
-
6445
-
6446
- /**
6447
- * read BIFF8 constant value which may be 'Empty Value', 'Number', 'String Value', 'Boolean Value', 'Error Value'
6448
- * section 2.5.7
6449
- * returns e.g. array('value' => '5', 'size' => 9)
6450
- *
6451
- * @param string $valueData
6452
- * @return array
6453
- */
6454
- private static function _readBIFF8Constant($valueData)
6455
- {
6456
- // offset: 0; size: 1; identifier for type of constant
6457
- $identifier = ord($valueData[0]);
6458
-
6459
- switch ($identifier) {
6460
- case 0x00: // empty constant (what is this?)
6461
- $value = '';
6462
- $size = 9;
6463
- break;
6464
- case 0x01: // number
6465
- // offset: 1; size: 8; IEEE 754 floating-point value
6466
- $value = self::_extractNumber(substr($valueData, 1, 8));
6467
- $size = 9;
6468
- break;
6469
- case 0x02: // string value
6470
- // offset: 1; size: var; Unicode string, 16-bit string length
6471
- $string = self::_readUnicodeStringLong(substr($valueData, 1));
6472
- $value = '"' . $string['value'] . '"';
6473
- $size = 1 + $string['size'];
6474
- break;
6475
- case 0x04: // boolean
6476
- // offset: 1; size: 1; 0 = FALSE, 1 = TRUE
6477
- if (ord($valueData[1])) {
6478
- $value = 'TRUE';
6479
- } else {
6480
- $value = 'FALSE';
6481
- }
6482
- $size = 9;
6483
- break;
6484
- case 0x10: // error code
6485
- // offset: 1; size: 1; error code
6486
- $value = self::_mapErrorCode(ord($valueData[1]));
6487
- $size = 9;
6488
- break;
6489
- }
6490
- return array(
6491
- 'value' => $value,
6492
- 'size' => $size,
6493
- );
6494
- }
6495
-
6496
-
6497
- /**
6498
- * Extract RGB color
6499
- * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.4
6500
- *
6501
- * @param string $rgb Encoded RGB value (4 bytes)
6502
- * @return array
6503
- */
6504
- private static function _readRGB($rgb)
6505
- {
6506
- // offset: 0; size 1; Red component
6507
- $r = ord($rgb{0});
6508
-
6509
- // offset: 1; size: 1; Green component
6510
- $g = ord($rgb{1});
6511
-
6512
- // offset: 2; size: 1; Blue component
6513
- $b = ord($rgb{2});
6514
-
6515
- // HEX notation, e.g. 'FF00FC'
6516
- $rgb = sprintf('%02X%02X%02X', $r, $g, $b);
6517
-
6518
- return array('rgb' => $rgb);
6519
- }
6520
-
6521
-
6522
- /**
6523
- * Read byte string (8-bit string length)
6524
- * OpenOffice documentation: 2.5.2
6525
- *
6526
- * @param string $subData
6527
- * @return array
6528
- */
6529
- private function _readByteStringShort($subData)
6530
- {
6531
- // offset: 0; size: 1; length of the string (character count)
6532
- $ln = ord($subData[0]);
6533
-
6534
- // offset: 1: size: var; character array (8-bit characters)
6535
- $value = $this->_decodeCodepage(substr($subData, 1, $ln));
6536
-
6537
- return array(
6538
- 'value' => $value,
6539
- 'size' => 1 + $ln, // size in bytes of data structure
6540
- );
6541
- }
6542
-
6543
-
6544
- /**
6545
- * Read byte string (16-bit string length)
6546
- * OpenOffice documentation: 2.5.2
6547
- *
6548
- * @param string $subData
6549
- * @return array
6550
- */
6551
- private function _readByteStringLong($subData)
6552
- {
6553
- // offset: 0; size: 2; length of the string (character count)
6554
- $ln = self::_GetInt2d($subData, 0);
6555
-
6556
- // offset: 2: size: var; character array (8-bit characters)
6557
- $value = $this->_decodeCodepage(substr($subData, 2));
6558
-
6559
- //return $string;
6560
- return array(
6561
- 'value' => $value,
6562
- 'size' => 2 + $ln, // size in bytes of data structure
6563
- );
6564
- }
6565
-
6566
-
6567
- /**
6568
- * Extracts an Excel Unicode short string (8-bit string length)
6569
- * OpenOffice documentation: 2.5.3
6570
- * function will automatically find out where the Unicode string ends.
6571
- *
6572
- * @param string $subData
6573
- * @return array
6574
- */
6575
- private static function _readUnicodeStringShort($subData)
6576
- {
6577
- $value = '';
6578
-
6579
- // offset: 0: size: 1; length of the string (character count)
6580
- $characterCount = ord($subData[0]);
6581
-
6582
- $string = self::_readUnicodeString(substr($subData, 1), $characterCount);
6583
-
6584
- // add 1 for the string length
6585
- $string['size'] += 1;
6586
-
6587
- return $string;
6588
- }
6589
-
6590
-
6591
- /**
6592
- * Extracts an Excel Unicode long string (16-bit string length)
6593
- * OpenOffice documentation: 2.5.3
6594
- * this function is under construction, needs to support rich text, and Asian phonetic settings
6595
- *
6596
- * @param string $subData
6597
- * @return array
6598
- */
6599
- private static function _readUnicodeStringLong($subData)
6600
- {
6601
- $value = '';
6602
-
6603
- // offset: 0: size: 2; length of the string (character count)
6604
- $characterCount = self::_GetInt2d($subData, 0);
6605
-
6606
- $string = self::_readUnicodeString(substr($subData, 2), $characterCount);
6607
-
6608
- // add 2 for the string length
6609
- $string['size'] += 2;
6610
-
6611
- return $string;
6612
- }
6613
-
6614
-
6615
- /**
6616
- * Read Unicode string with no string length field, but with known character count
6617
- * this function is under construction, needs to support rich text, and Asian phonetic settings
6618
- * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.3
6619
- *
6620
- * @param string $subData
6621
- * @param int $characterCount
6622
- * @return array
6623
- */
6624
- private static function _readUnicodeString($subData, $characterCount)
6625
- {
6626
- $value = '';
6627
-
6628
- // offset: 0: size: 1; option flags
6629
-
6630
- // bit: 0; mask: 0x01; character compression (0 = compressed 8-bit, 1 = uncompressed 16-bit)
6631
- $isCompressed = !((0x01 & ord($subData[0])) >> 0);
6632
-
6633
- // bit: 2; mask: 0x04; Asian phonetic settings
6634
- $hasAsian = (0x04) & ord($subData[0]) >> 2;
6635
-
6636
- // bit: 3; mask: 0x08; Rich-Text settings
6637
- $hasRichText = (0x08) & ord($subData[0]) >> 3;
6638
-
6639
- // offset: 1: size: var; character array
6640
- // this offset assumes richtext and Asian phonetic settings are off which is generally wrong
6641
- // needs to be fixed
6642
- $value = self::_encodeUTF16(substr($subData, 1, $isCompressed ? $characterCount : 2 * $characterCount), $isCompressed);
6643
-
6644
- return array(
6645
- 'value' => $value,
6646
- 'size' => $isCompressed ? 1 + $characterCount : 1 + 2 * $characterCount, // the size in bytes including the option flags
6647
- );
6648
- }
6649
-
6650
-
6651
- /**
6652
- * Convert UTF-8 string to string surounded by double quotes. Used for explicit string tokens in formulas.
6653
- * Example: hello"world --> "hello""world"
6654
- *
6655
- * @param string $value UTF-8 encoded string
6656
- * @return string
6657
- */
6658
- private static function _UTF8toExcelDoubleQuoted($value)
6659
- {
6660
- return '"' . str_replace('"', '""', $value) . '"';
6661
- }
6662
-
6663
-
6664
- /**
6665
- * Reads first 8 bytes of a string and return IEEE 754 float
6666
- *
6667
- * @param string $data Binary string that is at least 8 bytes long
6668
- * @return float
6669
- */
6670
- private static function _extractNumber($data)
6671
- {
6672
- $rknumhigh = self::_GetInt4d($data, 4);
6673
- $rknumlow = self::_GetInt4d($data, 0);
6674
- $sign = ($rknumhigh & 0x80000000) >> 31;
6675
- $exp = (($rknumhigh & 0x7ff00000) >> 20) - 1023;
6676
- $mantissa = (0x100000 | ($rknumhigh & 0x000fffff));
6677
- $mantissalow1 = ($rknumlow & 0x80000000) >> 31;
6678
- $mantissalow2 = ($rknumlow & 0x7fffffff);
6679
- $value = $mantissa / pow( 2 , (20 - $exp));
6680
-
6681
- if ($mantissalow1 != 0) {
6682
- $value += 1 / pow (2 , (21 - $exp));
6683
- }
6684
-
6685
- $value += $mantissalow2 / pow (2 , (52 - $exp));
6686
- if ($sign) {
6687
- $value *= -1;
6688
- }
6689
-
6690
- return $value;
6691
- }
6692
-
6693
-
6694
- private static function _GetIEEE754($rknum)
6695
- {
6696
- if (($rknum & 0x02) != 0) {
6697
- $value = $rknum >> 2;
6698
- } else {
6699
- // changes by mmp, info on IEEE754 encoding from
6700
- // research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
6701
- // The RK format calls for using only the most significant 30 bits
6702
- // of the 64 bit floating point value. The other 34 bits are assumed
6703
- // to be 0 so we use the upper 30 bits of $rknum as follows...
6704
- $sign = ($rknum & 0x80000000) >> 31;
6705
- $exp = ($rknum & 0x7ff00000) >> 20;
6706
- $mantissa = (0x100000 | ($rknum & 0x000ffffc));
6707
- $value = $mantissa / pow( 2 , (20- ($exp - 1023)));
6708
- if ($sign) {
6709
- $value = -1 * $value;
6710
- }
6711
- //end of changes by mmp
6712
- }
6713
- if (($rknum & 0x01) != 0) {
6714
- $value /= 100;
6715
- }
6716
- return $value;
6717
- }
6718
-
6719
-
6720
- /**
6721
- * Get UTF-8 string from (compressed or uncompressed) UTF-16 string
6722
- *
6723
- * @param string $string
6724
- * @param bool $compressed
6725
- * @return string
6726
- */
6727
- private static function _encodeUTF16($string, $compressed = '')
6728
- {
6729
- if ($compressed) {
6730
- $string = self::_uncompressByteString($string);
6731
- }
6732
-
6733
- return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', 'UTF-16LE');
6734
- }
6735
-
6736
-
6737
- /**
6738
- * Convert UTF-16 string in compressed notation to uncompressed form. Only used for BIFF8.
6739
- *
6740
- * @param string $string
6741
- * @return string
6742
- */
6743
- private static function _uncompressByteString($string)
6744
- {
6745
- $uncompressedString = '';
6746
- $strLen = strlen($string);
6747
- for ($i = 0; $i < $strLen; ++$i) {
6748
- $uncompressedString .= $string[$i] . "\0";
6749
- }
6750
-
6751
- return $uncompressedString;
6752
- }
6753
-
6754
-
6755
- /**
6756
- * Convert string to UTF-8. Only used for BIFF5.
6757
- *
6758
- * @param string $string
6759
- * @return string
6760
- */
6761
- private function _decodeCodepage($string)
6762
- {
6763
- return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', $this->_codepage);
6764
- }
6765
-
6766
-
6767
- /**
6768
- * Read 16-bit unsigned integer
6769
- *
6770
- * @param string $data
6771
- * @param int $pos
6772
- * @return int
6773
- */
6774
- public static function _GetInt2d($data, $pos)
6775
- {
6776
- return ord($data[$pos]) | (ord($data[$pos+1]) << 8);
6777
- }
6778
-
6779
-
6780
- /**
6781
- * Read 32-bit signed integer
6782
- *
6783
- * @param string $data
6784
- * @param int $pos
6785
- * @return int
6786
- */
6787
- public static function _GetInt4d($data, $pos)
6788
- {
6789
- // FIX: represent numbers correctly on 64-bit system
6790
- // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
6791
- // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
6792
- $_or_24 = ord($data[$pos + 3]);
6793
- if ($_or_24 >= 128) {
6794
- // negative number
6795
- $_ord_24 = -abs((256 - $_or_24) << 24);
6796
- } else {
6797
- $_ord_24 = ($_or_24 & 127) << 24;
6798
- }
6799
- return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $_ord_24;
6800
- }
6801
-
6802
-
6803
- /**
6804
- * Read color
6805
- *
6806
- * @param int $color Indexed color
6807
- * @param array $palette Color palette
6808
- * @return array RGB color value, example: array('rgb' => 'FF0000')
6809
- */
6810
- private static function _readColor($color,$palette,$version)
6811
- {
6812
- if ($color <= 0x07 || $color >= 0x40) {
6813
- // special built-in color
6814
- return self::_mapBuiltInColor($color);
6815
- } elseif (isset($palette) && isset($palette[$color - 8])) {
6816
- // palette color, color index 0x08 maps to pallete index 0
6817
- return $palette[$color - 8];
6818
- } else {
6819
- // default color table
6820
- if ($version == self::XLS_BIFF8) {
6821
- return self::_mapColor($color);
6822
- } else {
6823
- // BIFF5
6824
- return self::_mapColorBIFF5($color);
6825
- }
6826
- }
6827
-
6828
- return $color;
6829
- }
6830
-
6831
-
6832
- /**
6833
- * Map border style
6834
- * OpenOffice documentation: 2.5.11
6835
- *
6836
- * @param int $index
6837
- * @return string
6838
- */
6839
- private static function _mapBorderStyle($index)
6840
- {
6841
- switch ($index) {
6842
- case 0x00: return PHPExcel_Style_Border::BORDER_NONE;
6843
- case 0x01: return PHPExcel_Style_Border::BORDER_THIN;
6844
- case 0x02: return PHPExcel_Style_Border::BORDER_MEDIUM;
6845
- case 0x03: return PHPExcel_Style_Border::BORDER_DASHED;
6846
- case 0x04: return PHPExcel_Style_Border::BORDER_DOTTED;
6847
- case 0x05: return PHPExcel_Style_Border::BORDER_THICK;
6848
- case 0x06: return PHPExcel_Style_Border::BORDER_DOUBLE;
6849
- case 0x07: return PHPExcel_Style_Border::BORDER_HAIR;
6850
- case 0x08: return PHPExcel_Style_Border::BORDER_MEDIUMDASHED;
6851
- case 0x09: return PHPExcel_Style_Border::BORDER_DASHDOT;
6852
- case 0x0A: return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT;
6853
- case 0x0B: return PHPExcel_Style_Border::BORDER_DASHDOTDOT;
6854
- case 0x0C: return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT;
6855
- case 0x0D: return PHPExcel_Style_Border::BORDER_SLANTDASHDOT;
6856
- default: return PHPExcel_Style_Border::BORDER_NONE;
6857
- }
6858
- }
6859
-
6860
-
6861
- /**
6862
- * Get fill pattern from index
6863
- * OpenOffice documentation: 2.5.12
6864
- *
6865
- * @param int $index
6866
- * @return string
6867
- */
6868
- private static function _mapFillPattern($index)
6869
- {
6870
- switch ($index) {
6871
- case 0x00: return PHPExcel_Style_Fill::FILL_NONE;
6872
- case 0x01: return PHPExcel_Style_Fill::FILL_SOLID;
6873
- case 0x02: return PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY;
6874
- case 0x03: return PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY;
6875
- case 0x04: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY;
6876
- case 0x05: return PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL;
6877
- case 0x06: return PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL;
6878
- case 0x07: return PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN;
6879
- case 0x08: return PHPExcel_Style_Fill::FILL_PATTERN_DARKUP;
6880
- case 0x09: return PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID;
6881
- case 0x0A: return PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS;
6882
- case 0x0B: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL;
6883
- case 0x0C: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL;
6884
- case 0x0D: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN;
6885
- case 0x0E: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP;
6886
- case 0x0F: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID;
6887
- case 0x10: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS;
6888
- case 0x11: return PHPExcel_Style_Fill::FILL_PATTERN_GRAY125;
6889
- case 0x12: return PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625;
6890
- default: return PHPExcel_Style_Fill::FILL_NONE;
6891
- }
6892
- }
6893
-
6894
-
6895
- /**
6896
- * Map error code, e.g. '#N/A'
6897
- *
6898
- * @param int $subData
6899
- * @return string
6900
- */
6901
- private static function _mapErrorCode($subData)
6902
- {
6903
- switch ($subData) {
6904
- case 0x00: return '#NULL!'; break;
6905
- case 0x07: return '#DIV/0!'; break;
6906
- case 0x0F: return '#VALUE!'; break;
6907
- case 0x17: return '#REF!'; break;
6908
- case 0x1D: return '#NAME?'; break;
6909
- case 0x24: return '#NUM!'; break;
6910
- case 0x2A: return '#N/A'; break;
6911
- default: return false;
6912
- }
6913
- }
6914
-
6915
-
6916
- /**
6917
- * Map built-in color to RGB value
6918
- *
6919
- * @param int $color Indexed color
6920
- * @return array
6921
- */
6922
- private static function _mapBuiltInColor($color)
6923
- {
6924
- switch ($color) {
6925
- case 0x00: return array('rgb' => '000000');
6926
- case 0x01: return array('rgb' => 'FFFFFF');
6927
- case 0x02: return array('rgb' => 'FF0000');
6928
- case 0x03: return array('rgb' => '00FF00');
6929
- case 0x04: return array('rgb' => '0000FF');
6930
- case 0x05: return array('rgb' => 'FFFF00');
6931
- case 0x06: return array('rgb' => 'FF00FF');
6932
- case 0x07: return array('rgb' => '00FFFF');
6933
- case 0x40: return array('rgb' => '000000'); // system window text color
6934
- case 0x41: return array('rgb' => 'FFFFFF'); // system window background color
6935
- default: return array('rgb' => '000000');
6936
- }
6937
- }
6938
-
6939
-
6940
- /**
6941
- * Map color array from BIFF5 built-in color index
6942
- *
6943
- * @param int $subData
6944
- * @return array
6945
- */
6946
- private static function _mapColorBIFF5($subData)
6947
- {
6948
- switch ($subData) {
6949
- case 0x08: return array('rgb' => '000000');
6950
- case 0x09: return array('rgb' => 'FFFFFF');
6951
- case 0x0A: return array('rgb' => 'FF0000');
6952
- case 0x0B: return array('rgb' => '00FF00');
6953
- case 0x0C: return array('rgb' => '0000FF');
6954
- case 0x0D: return array('rgb' => 'FFFF00');
6955
- case 0x0E: return array('rgb' => 'FF00FF');
6956
- case 0x0F: return array('rgb' => '00FFFF');
6957
- case 0x10: return array('rgb' => '800000');
6958
- case 0x11: return array('rgb' => '008000');
6959
- case 0x12: return array('rgb' => '000080');
6960
- case 0x13: return array('rgb' => '808000');
6961
- case 0x14: return array('rgb' => '800080');
6962
- case 0x15: return array('rgb' => '008080');
6963
- case 0x16: return array('rgb' => 'C0C0C0');
6964
- case 0x17: return array('rgb' => '808080');
6965
- case 0x18: return array('rgb' => '8080FF');
6966
- case 0x19: return array('rgb' => '802060');
6967
- case 0x1A: return array('rgb' => 'FFFFC0');
6968
- case 0x1B: return array('rgb' => 'A0E0F0');
6969
- case 0x1C: return array('rgb' => '600080');
6970
- case 0x1D: return array('rgb' => 'FF8080');
6971
- case 0x1E: return array('rgb' => '0080C0');
6972
- case 0x1F: return array('rgb' => 'C0C0FF');
6973
- case 0x20: return array('rgb' => '000080');
6974
- case 0x21: return array('rgb' => 'FF00FF');
6975
- case 0x22: return array('rgb' => 'FFFF00');
6976
- case 0x23: return array('rgb' => '00FFFF');
6977
- case 0x24: return array('rgb' => '800080');
6978
- case 0x25: return array('rgb' => '800000');
6979
- case 0x26: return array('rgb' => '008080');
6980
- case 0x27: return array('rgb' => '0000FF');
6981
- case 0x28: return array('rgb' => '00CFFF');
6982
- case 0x29: return array('rgb' => '69FFFF');
6983
- case 0x2A: return array('rgb' => 'E0FFE0');
6984
- case 0x2B: return array('rgb' => 'FFFF80');
6985
- case 0x2C: return array('rgb' => 'A6CAF0');
6986
- case 0x2D: return array('rgb' => 'DD9CB3');
6987
- case 0x2E: return array('rgb' => 'B38FEE');
6988
- case 0x2F: return array('rgb' => 'E3E3E3');
6989
- case 0x30: return array('rgb' => '2A6FF9');
6990
- case 0x31: return array('rgb' => '3FB8CD');
6991
- case 0x32: return array('rgb' => '488436');
6992
- case 0x33: return array('rgb' => '958C41');
6993
- case 0x34: return array('rgb' => '8E5E42');
6994
- case 0x35: return array('rgb' => 'A0627A');
6995
- case 0x36: return array('rgb' => '624FAC');
6996
- case 0x37: return array('rgb' => '969696');
6997
- case 0x38: return array('rgb' => '1D2FBE');
6998
- case 0x39: return array('rgb' => '286676');
6999
- case 0x3A: return array('rgb' => '004500');
7000
- case 0x3B: return array('rgb' => '453E01');
7001
- case 0x3C: return array('rgb' => '6A2813');
7002
- case 0x3D: return array('rgb' => '85396A');
7003
- case 0x3E: return array('rgb' => '4A3285');
7004
- case 0x3F: return array('rgb' => '424242');
7005
- default: return array('rgb' => '000000');
7006
- }
7007
- }
7008
-
7009
-
7010
- /**
7011
- * Map color array from BIFF8 built-in color index
7012
- *
7013
- * @param int $subData
7014
- * @return array
7015
- */
7016
- private static function _mapColor($subData)
7017
- {
7018
- switch ($subData) {
7019
- case 0x08: return array('rgb' => '000000');
7020
- case 0x09: return array('rgb' => 'FFFFFF');
7021
- case 0x0A: return array('rgb' => 'FF0000');
7022
- case 0x0B: return array('rgb' => '00FF00');
7023
- case 0x0C: return array('rgb' => '0000FF');
7024
- case 0x0D: return array('rgb' => 'FFFF00');
7025
- case 0x0E: return array('rgb' => 'FF00FF');
7026
- case 0x0F: return array('rgb' => '00FFFF');
7027
- case 0x10: return array('rgb' => '800000');
7028
- case 0x11: return array('rgb' => '008000');
7029
- case 0x12: return array('rgb' => '000080');
7030
- case 0x13: return array('rgb' => '808000');
7031
- case 0x14: return array('rgb' => '800080');
7032
- case 0x15: return array('rgb' => '008080');
7033
- case 0x16: return array('rgb' => 'C0C0C0');
7034
- case 0x17: return array('rgb' => '808080');
7035
- case 0x18: return array('rgb' => '9999FF');
7036
- case 0x19: return array('rgb' => '993366');
7037
- case 0x1A: return array('rgb' => 'FFFFCC');
7038
- case 0x1B: return array('rgb' => 'CCFFFF');
7039
- case 0x1C: return array('rgb' => '660066');
7040
- case 0x1D: return array('rgb' => 'FF8080');
7041
- case 0x1E: return array('rgb' => '0066CC');
7042
- case 0x1F: return array('rgb' => 'CCCCFF');
7043
- case 0x20: return array('rgb' => '000080');
7044
- case 0x21: return array('rgb' => 'FF00FF');
7045
- case 0x22: return array('rgb' => 'FFFF00');
7046
- case 0x23: return array('rgb' => '00FFFF');
7047
- case 0x24: return array('rgb' => '800080');
7048
- case 0x25: return array('rgb' => '800000');
7049
- case 0x26: return array('rgb' => '008080');
7050
- case 0x27: return array('rgb' => '0000FF');
7051
- case 0x28: return array('rgb' => '00CCFF');
7052
- case 0x29: return array('rgb' => 'CCFFFF');
7053
- case 0x2A: return array('rgb' => 'CCFFCC');
7054
- case 0x2B: return array('rgb' => 'FFFF99');
7055
- case 0x2C: return array('rgb' => '99CCFF');
7056
- case 0x2D: return array('rgb' => 'FF99CC');
7057
- case 0x2E: return array('rgb' => 'CC99FF');
7058
- case 0x2F: return array('rgb' => 'FFCC99');
7059
- case 0x30: return array('rgb' => '3366FF');
7060
- case 0x31: return array('rgb' => '33CCCC');
7061
- case 0x32: return array('rgb' => '99CC00');
7062
- case 0x33: return array('rgb' => 'FFCC00');
7063
- case 0x34: return array('rgb' => 'FF9900');
7064
- case 0x35: return array('rgb' => 'FF6600');
7065
- case 0x36: return array('rgb' => '666699');
7066
- case 0x37: return array('rgb' => '969696');
7067
- case 0x38: return array('rgb' => '003366');
7068
- case 0x39: return array('rgb' => '339966');
7069
- case 0x3A: return array('rgb' => '003300');
7070
- case 0x3B: return array('rgb' => '333300');
7071
- case 0x3C: return array('rgb' => '993300');
7072
- case 0x3D: return array('rgb' => '993366');
7073
- case 0x3E: return array('rgb' => '333399');
7074
- case 0x3F: return array('rgb' => '333333');
7075
- default: return array('rgb' => '000000');
7076
- }
7077
- }
7078
-
7079
-
7080
- private function _parseRichText($is = '') {
7081
- $value = new PHPExcel_RichText();
7082
-
7083
- $value->createText($is);
7084
-
7085
- return $value;
7086
- }
7087
-
7088
- }
1
+ <?php
2
+ /**
3
+ * PHPExcel
4
+ *
5
+ * Copyright (c) 2006 - 2014 PHPExcel
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ * @category PHPExcel
22
+ * @package PHPExcel_Reader_Excel5
23
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25
+ * @version ##VERSION##, ##DATE##
26
+ */
27
+
28
+ // Original file header of ParseXL (used as the base for this class):
29
+ // --------------------------------------------------------------------------------
30
+ // Adapted from Excel_Spreadsheet_Reader developed by users bizon153,
31
+ // trex005, and mmp11 (SourceForge.net)
32
+ // http://sourceforge.net/projects/phpexcelreader/
33
+ // Primary changes made by canyoncasa (dvc) for ParseXL 1.00 ...
34
+ // Modelled moreso after Perl Excel Parse/Write modules
35
+ // Added Parse_Excel_Spreadsheet object
36
+ // Reads a whole worksheet or tab as row,column array or as
37
+ // associated hash of indexed rows and named column fields
38
+ // Added variables for worksheet (tab) indexes and names
39
+ // Added an object call for loading individual woorksheets
40
+ // Changed default indexing defaults to 0 based arrays
41
+ // Fixed date/time and percent formats
42
+ // Includes patches found at SourceForge...
43
+ // unicode patch by nobody
44
+ // unpack("d") machine depedency patch by matchy
45
+ // boundsheet utf16 patch by bjaenichen
46
+ // Renamed functions for shorter names
47
+ // General code cleanup and rigor, including <80 column width
48
+ // Included a testcase Excel file and PHP example calls
49
+ // Code works for PHP 5.x
50
+
51
+ // Primary changes made by canyoncasa (dvc) for ParseXL 1.10 ...
52
+ // http://sourceforge.net/tracker/index.php?func=detail&aid=1466964&group_id=99160&atid=623334
53
+ // Decoding of formula conditions, results, and tokens.
54
+ // Support for user-defined named cells added as an array "namedcells"
55
+ // Patch code for user-defined named cells supports single cells only.
56
+ // NOTE: this patch only works for BIFF8 as BIFF5-7 use a different
57
+ // external sheet reference structure
58
+
59
+
60
+ /** PHPExcel root directory */
61
+ if (!defined('PHPEXCEL_ROOT')) {
62
+ /**
63
+ * @ignore
64
+ */
65
+ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
66
+ require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
67
+ }
68
+
69
+ /**
70
+ * PHPExcel_Reader_Excel5
71
+ *
72
+ * This class uses {@link http://sourceforge.net/projects/phpexcelreader/parseXL}
73
+ *
74
+ * @category PHPExcel
75
+ * @package PHPExcel_Reader_Excel5
76
+ * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
77
+ */
78
+ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
79
+ {
80
+ // ParseXL definitions
81
+ const XLS_BIFF8 = 0x0600;
82
+ const XLS_BIFF7 = 0x0500;
83
+ const XLS_WorkbookGlobals = 0x0005;
84
+ const XLS_Worksheet = 0x0010;
85
+
86
+ // record identifiers
87
+ const XLS_Type_FORMULA = 0x0006;
88
+ const XLS_Type_EOF = 0x000a;
89
+ const XLS_Type_PROTECT = 0x0012;
90
+ const XLS_Type_OBJECTPROTECT = 0x0063;
91
+ const XLS_Type_SCENPROTECT = 0x00dd;
92
+ const XLS_Type_PASSWORD = 0x0013;
93
+ const XLS_Type_HEADER = 0x0014;
94
+ const XLS_Type_FOOTER = 0x0015;
95
+ const XLS_Type_EXTERNSHEET = 0x0017;
96
+ const XLS_Type_DEFINEDNAME = 0x0018;
97
+ const XLS_Type_VERTICALPAGEBREAKS = 0x001a;
98
+ const XLS_Type_HORIZONTALPAGEBREAKS = 0x001b;
99
+ const XLS_Type_NOTE = 0x001c;
100
+ const XLS_Type_SELECTION = 0x001d;
101
+ const XLS_Type_DATEMODE = 0x0022;
102
+ const XLS_Type_EXTERNNAME = 0x0023;
103
+ const XLS_Type_LEFTMARGIN = 0x0026;
104
+ const XLS_Type_RIGHTMARGIN = 0x0027;
105
+ const XLS_Type_TOPMARGIN = 0x0028;
106
+ const XLS_Type_BOTTOMMARGIN = 0x0029;
107
+ const XLS_Type_PRINTGRIDLINES = 0x002b;
108
+ const XLS_Type_FILEPASS = 0x002f;
109
+ const XLS_Type_FONT = 0x0031;
110
+ const XLS_Type_CONTINUE = 0x003c;
111
+ const XLS_Type_PANE = 0x0041;
112
+ const XLS_Type_CODEPAGE = 0x0042;
113
+ const XLS_Type_DEFCOLWIDTH = 0x0055;
114
+ const XLS_Type_OBJ = 0x005d;
115
+ const XLS_Type_COLINFO = 0x007d;
116
+ const XLS_Type_IMDATA = 0x007f;
117
+ const XLS_Type_SHEETPR = 0x0081;
118
+ const XLS_Type_HCENTER = 0x0083;
119
+ const XLS_Type_VCENTER = 0x0084;
120
+ const XLS_Type_SHEET = 0x0085;
121
+ const XLS_Type_PALETTE = 0x0092;
122
+ const XLS_Type_SCL = 0x00a0;
123
+ const XLS_Type_PAGESETUP = 0x00a1;
124
+ const XLS_Type_MULRK = 0x00bd;
125
+ const XLS_Type_MULBLANK = 0x00be;
126
+ const XLS_Type_DBCELL = 0x00d7;
127
+ const XLS_Type_XF = 0x00e0;
128
+ const XLS_Type_MERGEDCELLS = 0x00e5;
129
+ const XLS_Type_MSODRAWINGGROUP = 0x00eb;
130
+ const XLS_Type_MSODRAWING = 0x00ec;
131
+ const XLS_Type_SST = 0x00fc;
132
+ const XLS_Type_LABELSST = 0x00fd;
133
+ const XLS_Type_EXTSST = 0x00ff;
134
+ const XLS_Type_EXTERNALBOOK = 0x01ae;
135
+ const XLS_Type_DATAVALIDATIONS = 0x01b2;
136
+ const XLS_Type_TXO = 0x01b6;
137
+ const XLS_Type_HYPERLINK = 0x01b8;
138
+ const XLS_Type_DATAVALIDATION = 0x01be;
139
+ const XLS_Type_DIMENSION = 0x0200;
140
+ const XLS_Type_BLANK = 0x0201;
141
+ const XLS_Type_NUMBER = 0x0203;
142
+ const XLS_Type_LABEL = 0x0204;
143
+ const XLS_Type_BOOLERR = 0x0205;
144
+ const XLS_Type_STRING = 0x0207;
145
+ const XLS_Type_ROW = 0x0208;
146
+ const XLS_Type_INDEX = 0x020b;
147
+ const XLS_Type_ARRAY = 0x0221;
148
+ const XLS_Type_DEFAULTROWHEIGHT = 0x0225;
149
+ const XLS_Type_WINDOW2 = 0x023e;
150
+ const XLS_Type_RK = 0x027e;
151
+ const XLS_Type_STYLE = 0x0293;
152
+ const XLS_Type_FORMAT = 0x041e;
153
+ const XLS_Type_SHAREDFMLA = 0x04bc;
154
+ const XLS_Type_BOF = 0x0809;
155
+ const XLS_Type_SHEETPROTECTION = 0x0867;
156
+ const XLS_Type_RANGEPROTECTION = 0x0868;
157
+ const XLS_Type_SHEETLAYOUT = 0x0862;
158
+ const XLS_Type_XFEXT = 0x087d;
159
+ const XLS_Type_PAGELAYOUTVIEW = 0x088b;
160
+ const XLS_Type_UNKNOWN = 0xffff;
161
+
162
+ // Encryption type
163
+ const MS_BIFF_CRYPTO_NONE = 0;
164
+ const MS_BIFF_CRYPTO_XOR = 1;
165
+ const MS_BIFF_CRYPTO_RC4 = 2;
166
+
167
+ // Size of stream blocks when using RC4 encryption
168
+ const REKEY_BLOCK = 0x400;
169
+
170
+ /**
171
+ * Summary Information stream data.
172
+ *
173
+ * @var string
174
+ */
175
+ private $_summaryInformation;
176
+
177
+ /**
178
+ * Extended Summary Information stream data.
179
+ *
180
+ * @var string
181
+ */
182
+ private $_documentSummaryInformation;
183
+
184
+ /**
185
+ * User-Defined Properties stream data.
186
+ *
187
+ * @var string
188
+ */
189
+ private $_userDefinedProperties;
190
+
191
+ /**
192
+ * Workbook stream data. (Includes workbook globals substream as well as sheet substreams)
193
+ *
194
+ * @var string
195
+ */
196
+ private $_data;
197
+
198
+ /**
199
+ * Size in bytes of $this->_data
200
+ *
201
+ * @var int
202
+ */
203
+ private $_dataSize;
204
+
205
+ /**
206
+ * Current position in stream
207
+ *
208
+ * @var integer
209
+ */
210
+ private $_pos;
211
+
212
+ /**
213
+ * Workbook to be returned by the reader.
214
+ *
215
+ * @var PHPExcel
216
+ */
217
+ private $_phpExcel;
218
+
219
+ /**
220
+ * Worksheet that is currently being built by the reader.
221
+ *
222
+ * @var PHPExcel_Worksheet
223
+ */
224
+ private $_phpSheet;
225
+
226
+ /**
227
+ * BIFF version
228
+ *
229
+ * @var int
230
+ */
231
+ private $_version;
232
+
233
+ /**
234
+ * Codepage set in the Excel file being read. Only important for BIFF5 (Excel 5.0 - Excel 95)
235
+ * For BIFF8 (Excel 97 - Excel 2003) this will always have the value 'UTF-16LE'
236
+ *
237
+ * @var string
238
+ */
239
+ private $_codepage;
240
+
241
+ /**
242
+ * Shared formats
243
+ *
244
+ * @var array
245
+ */
246
+ private $_formats;
247
+
248
+ /**
249
+ * Shared fonts
250
+ *
251
+ * @var array
252
+ */
253
+ private $_objFonts;
254
+
255
+ /**
256
+ * Color palette
257
+ *
258
+ * @var array
259
+ */
260
+ private $_palette;
261
+
262
+ /**
263
+ * Worksheets
264
+ *
265
+ * @var array
266
+ */
267
+ private $_sheets;
268
+
269
+ /**
270
+ * External books
271
+ *
272
+ * @var array
273
+ */
274
+ private $_externalBooks;
275
+
276
+ /**
277
+ * REF structures. Only applies to BIFF8.
278
+ *
279
+ * @var array
280
+ */
281
+ private $_ref;
282
+
283
+ /**
284
+ * External names
285
+ *
286
+ * @var array
287
+ */
288
+ private $_externalNames;
289
+
290
+ /**
291
+ * Defined names
292
+ *
293
+ * @var array
294
+ */
295
+ private $_definedname;
296
+
297
+ /**
298
+ * Shared strings. Only applies to BIFF8.
299
+ *
300
+ * @var array
301
+ */
302
+ private $_sst;
303
+
304
+ /**
305
+ * Panes are frozen? (in sheet currently being read). See WINDOW2 record.
306
+ *
307
+ * @var boolean
308
+ */
309
+ private $_frozen;
310
+
311
+ /**
312
+ * Fit printout to number of pages? (in sheet currently being read). See SHEETPR record.
313
+ *
314
+ * @var boolean
315
+ */
316
+ private $_isFitToPages;
317
+
318
+ /**
319
+ * Objects. One OBJ record contributes with one entry.
320
+ *
321
+ * @var array
322
+ */
323
+ private $_objs;
324
+
325
+ /**
326
+ * Text Objects. One TXO record corresponds with one entry.
327
+ *
328
+ * @var array
329
+ */
330
+ private $_textObjects;
331
+
332
+ /**
333
+ * Cell Annotations (BIFF8)
334
+ *
335
+ * @var array
336
+ */
337
+ private $_cellNotes;
338
+
339
+ /**
340
+ * The combined MSODRAWINGGROUP data
341
+ *
342
+ * @var string
343
+ */
344
+ private $_drawingGroupData;
345
+
346
+ /**
347
+ * The combined MSODRAWING data (per sheet)
348
+ *
349
+ * @var string
350
+ */
351
+ private $_drawingData;
352
+
353
+ /**
354
+ * Keep track of XF index
355
+ *
356
+ * @var int
357
+ */
358
+ private $_xfIndex;
359
+
360
+ /**
361
+ * Mapping of XF index (that is a cell XF) to final index in cellXf collection
362
+ *
363
+ * @var array
364
+ */
365
+ private $_mapCellXfIndex;
366
+
367
+ /**
368
+ * Mapping of XF index (that is a style XF) to final index in cellStyleXf collection
369
+ *
370
+ * @var array
371
+ */
372
+ private $_mapCellStyleXfIndex;
373
+
374
+ /**
375
+ * The shared formulas in a sheet. One SHAREDFMLA record contributes with one value.
376
+ *
377
+ * @var array
378
+ */
379
+ private $_sharedFormulas;
380
+
381
+ /**
382
+ * The shared formula parts in a sheet. One FORMULA record contributes with one value if it
383
+ * refers to a shared formula.
384
+ *
385
+ * @var array
386
+ */
387
+ private $_sharedFormulaParts;
388
+
389
+ /**
390
+ * The type of encryption in use
391
+ *
392
+ * @var int
393
+ */
394
+ private $_encryption = 0;
395
+
396
+ /**
397
+ * The position in the stream after which contents are encrypted
398
+ *
399
+ * @var int
400
+ */
401
+ private $_encryptionStartPos = false;
402
+
403
+ /**
404
+ * The current RC4 decryption object
405
+ *
406
+ * @var PHPExcel_Reader_Excel5_RC4
407
+ */
408
+ private $_rc4Key = null;
409
+
410
+ /**
411
+ * The position in the stream that the RC4 decryption object was left at
412
+ *
413
+ * @var int
414
+ */
415
+ private $_rc4Pos = 0;
416
+
417
+ /**
418
+ * The current MD5 context state
419
+ *
420
+ * @var string
421
+ */
422
+ private $_md5Ctxt = null;
423
+
424
+ /**
425
+ * Create a new PHPExcel_Reader_Excel5 instance
426
+ */
427
+ public function __construct() {
428
+ $this->_readFilter = new PHPExcel_Reader_DefaultReadFilter();
429
+ }
430
+
431
+
432
+ /**
433
+ * Can the current PHPExcel_Reader_IReader read the file?
434
+ *
435
+ * @param string $pFilename
436
+ * @return boolean
437
+ * @throws PHPExcel_Reader_Exception
438
+ */
439
+ public function canRead($pFilename)
440
+ {
441
+ // Check if file exists
442
+ if (!file_exists($pFilename)) {
443
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
444
+ }
445
+
446
+ try {
447
+ // Use ParseXL for the hard work.
448
+ $ole = new PHPExcel_Shared_OLERead();
449
+
450
+ // get excel data
451
+ $res = $ole->read($pFilename);
452
+ return true;
453
+ } catch (PHPExcel_Exception $e) {
454
+ return false;
455
+ }
456
+ }
457
+
458
+
459
+ /**
460
+ * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
461
+ *
462
+ * @param string $pFilename
463
+ * @throws PHPExcel_Reader_Exception
464
+ */
465
+ public function listWorksheetNames($pFilename)
466
+ {
467
+ // Check if file exists
468
+ if (!file_exists($pFilename)) {
469
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
470
+ }
471
+
472
+ $worksheetNames = array();
473
+
474
+ // Read the OLE file
475
+ $this->_loadOLE($pFilename);
476
+
477
+ // total byte size of Excel data (workbook global substream + sheet substreams)
478
+ $this->_dataSize = strlen($this->_data);
479
+
480
+ $this->_pos = 0;
481
+ $this->_sheets = array();
482
+
483
+ // Parse Workbook Global Substream
484
+ while ($this->_pos < $this->_dataSize) {
485
+ $code = self::_GetInt2d($this->_data, $this->_pos);
486
+
487
+ switch ($code) {
488
+ case self::XLS_Type_BOF: $this->_readBof(); break;
489
+ case self::XLS_Type_SHEET: $this->_readSheet(); break;
490
+ case self::XLS_Type_EOF: $this->_readDefault(); break 2;
491
+ default: $this->_readDefault(); break;
492
+ }
493
+ }
494
+
495
+ foreach ($this->_sheets as $sheet) {
496
+ if ($sheet['sheetType'] != 0x00) {
497
+ // 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
498
+ continue;
499
+ }
500
+
501
+ $worksheetNames[] = $sheet['name'];
502
+ }
503
+
504
+ return $worksheetNames;
505
+ }
506
+
507
+
508
+ /**
509
+ * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
510
+ *
511
+ * @param string $pFilename
512
+ * @throws PHPExcel_Reader_Exception
513
+ */
514
+ public function listWorksheetInfo($pFilename)
515
+ {
516
+ // Check if file exists
517
+ if (!file_exists($pFilename)) {
518
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
519
+ }
520
+
521
+ $worksheetInfo = array();
522
+
523
+ // Read the OLE file
524
+ $this->_loadOLE($pFilename);
525
+
526
+ // total byte size of Excel data (workbook global substream + sheet substreams)
527
+ $this->_dataSize = strlen($this->_data);
528
+
529
+ // initialize
530
+ $this->_pos = 0;
531
+ $this->_sheets = array();
532
+
533
+ // Parse Workbook Global Substream
534
+ while ($this->_pos < $this->_dataSize) {
535
+ $code = self::_GetInt2d($this->_data, $this->_pos);
536
+
537
+ switch ($code) {
538
+ case self::XLS_Type_BOF: $this->_readBof(); break;
539
+ case self::XLS_Type_SHEET: $this->_readSheet(); break;
540
+ case self::XLS_Type_EOF: $this->_readDefault(); break 2;
541
+ default: $this->_readDefault(); break;
542
+ }
543
+ }
544
+
545
+ // Parse the individual sheets
546
+ foreach ($this->_sheets as $sheet) {
547
+
548
+ if ($sheet['sheetType'] != 0x00) {
549
+ // 0x00: Worksheet
550
+ // 0x02: Chart
551
+ // 0x06: Visual Basic module
552
+ continue;
553
+ }
554
+
555
+ $tmpInfo = array();
556
+ $tmpInfo['worksheetName'] = $sheet['name'];
557
+ $tmpInfo['lastColumnLetter'] = 'A';
558
+ $tmpInfo['lastColumnIndex'] = 0;
559
+ $tmpInfo['totalRows'] = 0;
560
+ $tmpInfo['totalColumns'] = 0;
561
+
562
+ $this->_pos = $sheet['offset'];
563
+
564
+ while ($this->_pos <= $this->_dataSize - 4) {
565
+ $code = self::_GetInt2d($this->_data, $this->_pos);
566
+
567
+ switch ($code) {
568
+ case self::XLS_Type_RK:
569
+ case self::XLS_Type_LABELSST:
570
+ case self::XLS_Type_NUMBER:
571
+ case self::XLS_Type_FORMULA:
572
+ case self::XLS_Type_BOOLERR:
573
+ case self::XLS_Type_LABEL:
574
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
575
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
576
+
577
+ // move stream pointer to next record
578
+ $this->_pos += 4 + $length;
579
+
580
+ $rowIndex = self::_GetInt2d($recordData, 0) + 1;
581
+ $columnIndex = self::_GetInt2d($recordData, 2);
582
+
583
+ $tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
584
+ $tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
585
+ break;
586
+ case self::XLS_Type_BOF: $this->_readBof(); break;
587
+ case self::XLS_Type_EOF: $this->_readDefault(); break 2;
588
+ default: $this->_readDefault(); break;
589
+ }
590
+ }
591
+
592
+ $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
593
+ $tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
594
+
595
+ $worksheetInfo[] = $tmpInfo;
596
+ }
597
+
598
+ return $worksheetInfo;
599
+ }
600
+
601
+
602
+ /**
603
+ * Loads PHPExcel from file
604
+ *
605
+ * @param string $pFilename
606
+ * @return PHPExcel
607
+ * @throws PHPExcel_Reader_Exception
608
+ */
609
+ public function load($pFilename)
610
+ {
611
+ // Read the OLE file
612
+ $this->_loadOLE($pFilename);
613
+
614
+ // Initialisations
615
+ $this->_phpExcel = new PHPExcel;
616
+ $this->_phpExcel->removeSheetByIndex(0); // remove 1st sheet
617
+ if (!$this->_readDataOnly) {
618
+ $this->_phpExcel->removeCellStyleXfByIndex(0); // remove the default style
619
+ $this->_phpExcel->removeCellXfByIndex(0); // remove the default style
620
+ }
621
+
622
+ // Read the summary information stream (containing meta data)
623
+ $this->_readSummaryInformation();
624
+
625
+ // Read the Additional document summary information stream (containing application-specific meta data)
626
+ $this->_readDocumentSummaryInformation();
627
+
628
+ // total byte size of Excel data (workbook global substream + sheet substreams)
629
+ $this->_dataSize = strlen($this->_data);
630
+
631
+ // initialize
632
+ $this->_pos = 0;
633
+ $this->_codepage = 'CP1252';
634
+ $this->_formats = array();
635
+ $this->_objFonts = array();
636
+ $this->_palette = array();
637
+ $this->_sheets = array();
638
+ $this->_externalBooks = array();
639
+ $this->_ref = array();
640
+ $this->_definedname = array();
641
+ $this->_sst = array();
642
+ $this->_drawingGroupData = '';
643
+ $this->_xfIndex = '';
644
+ $this->_mapCellXfIndex = array();
645
+ $this->_mapCellStyleXfIndex = array();
646
+
647
+ // Parse Workbook Global Substream
648
+ while ($this->_pos < $this->_dataSize) {
649
+ $code = self::_GetInt2d($this->_data, $this->_pos);
650
+
651
+ switch ($code) {
652
+ case self::XLS_Type_BOF: $this->_readBof(); break;
653
+ case self::XLS_Type_FILEPASS: $this->_readFilepass(); break;
654
+ case self::XLS_Type_CODEPAGE: $this->_readCodepage(); break;
655
+ case self::XLS_Type_DATEMODE: $this->_readDateMode(); break;
656
+ case self::XLS_Type_FONT: $this->_readFont(); break;
657
+ case self::XLS_Type_FORMAT: $this->_readFormat(); break;
658
+ case self::XLS_Type_XF: $this->_readXf(); break;
659
+ case self::XLS_Type_XFEXT: $this->_readXfExt(); break;
660
+ case self::XLS_Type_STYLE: $this->_readStyle(); break;
661
+ case self::XLS_Type_PALETTE: $this->_readPalette(); break;
662
+ case self::XLS_Type_SHEET: $this->_readSheet(); break;
663
+ case self::XLS_Type_EXTERNALBOOK: $this->_readExternalBook(); break;
664
+ case self::XLS_Type_EXTERNNAME: $this->_readExternName(); break;
665
+ case self::XLS_Type_EXTERNSHEET: $this->_readExternSheet(); break;
666
+ case self::XLS_Type_DEFINEDNAME: $this->_readDefinedName(); break;
667
+ case self::XLS_Type_MSODRAWINGGROUP: $this->_readMsoDrawingGroup(); break;
668
+ case self::XLS_Type_SST: $this->_readSst(); break;
669
+ case self::XLS_Type_EOF: $this->_readDefault(); break 2;
670
+ default: $this->_readDefault(); break;
671
+ }
672
+ }
673
+
674
+ // Resolve indexed colors for font, fill, and border colors
675
+ // Cannot be resolved already in XF record, because PALETTE record comes afterwards
676
+ if (!$this->_readDataOnly) {
677
+ foreach ($this->_objFonts as $objFont) {
678
+ if (isset($objFont->colorIndex)) {
679
+ $color = self::_readColor($objFont->colorIndex,$this->_palette,$this->_version);
680
+ $objFont->getColor()->setRGB($color['rgb']);
681
+ }
682
+ }
683
+
684
+ foreach ($this->_phpExcel->getCellXfCollection() as $objStyle) {
685
+ // fill start and end color
686
+ $fill = $objStyle->getFill();
687
+
688
+ if (isset($fill->startcolorIndex)) {
689
+ $startColor = self::_readColor($fill->startcolorIndex,$this->_palette,$this->_version);
690
+ $fill->getStartColor()->setRGB($startColor['rgb']);
691
+ }
692
+
693
+ if (isset($fill->endcolorIndex)) {
694
+ $endColor = self::_readColor($fill->endcolorIndex,$this->_palette,$this->_version);
695
+ $fill->getEndColor()->setRGB($endColor['rgb']);
696
+ }
697
+
698
+ // border colors
699
+ $top = $objStyle->getBorders()->getTop();
700
+ $right = $objStyle->getBorders()->getRight();
701
+ $bottom = $objStyle->getBorders()->getBottom();
702
+ $left = $objStyle->getBorders()->getLeft();
703
+ $diagonal = $objStyle->getBorders()->getDiagonal();
704
+
705
+ if (isset($top->colorIndex)) {
706
+ $borderTopColor = self::_readColor($top->colorIndex,$this->_palette,$this->_version);
707
+ $top->getColor()->setRGB($borderTopColor['rgb']);
708
+ }
709
+
710
+ if (isset($right->colorIndex)) {
711
+ $borderRightColor = self::_readColor($right->colorIndex,$this->_palette,$this->_version);
712
+ $right->getColor()->setRGB($borderRightColor['rgb']);
713
+ }
714
+
715
+ if (isset($bottom->colorIndex)) {
716
+ $borderBottomColor = self::_readColor($bottom->colorIndex,$this->_palette,$this->_version);
717
+ $bottom->getColor()->setRGB($borderBottomColor['rgb']);
718
+ }
719
+
720
+ if (isset($left->colorIndex)) {
721
+ $borderLeftColor = self::_readColor($left->colorIndex,$this->_palette,$this->_version);
722
+ $left->getColor()->setRGB($borderLeftColor['rgb']);
723
+ }
724
+
725
+ if (isset($diagonal->colorIndex)) {
726
+ $borderDiagonalColor = self::_readColor($diagonal->colorIndex,$this->_palette,$this->_version);
727
+ $diagonal->getColor()->setRGB($borderDiagonalColor['rgb']);
728
+ }
729
+ }
730
+ }
731
+
732
+ // treat MSODRAWINGGROUP records, workbook-level Escher
733
+ if (!$this->_readDataOnly && $this->_drawingGroupData) {
734
+ $escherWorkbook = new PHPExcel_Shared_Escher();
735
+ $reader = new PHPExcel_Reader_Excel5_Escher($escherWorkbook);
736
+ $escherWorkbook = $reader->load($this->_drawingGroupData);
737
+
738
+ // debug Escher stream
739
+ //$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
740
+ //$debug->load($this->_drawingGroupData);
741
+ }
742
+
743
+ // Parse the individual sheets
744
+ foreach ($this->_sheets as $sheet) {
745
+
746
+ if ($sheet['sheetType'] != 0x00) {
747
+ // 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
748
+ continue;
749
+ }
750
+
751
+ // check if sheet should be skipped
752
+ if (isset($this->_loadSheetsOnly) && !in_array($sheet['name'], $this->_loadSheetsOnly)) {
753
+ continue;
754
+ }
755
+
756
+ // add sheet to PHPExcel object
757
+ $this->_phpSheet = $this->_phpExcel->createSheet();
758
+ // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
759
+ // cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
760
+ // name in line with the formula, not the reverse
761
+ $this->_phpSheet->setTitle($sheet['name'],false);
762
+ $this->_phpSheet->setSheetState($sheet['sheetState']);
763
+
764
+ $this->_pos = $sheet['offset'];
765
+
766
+ // Initialize isFitToPages. May change after reading SHEETPR record.
767
+ $this->_isFitToPages = false;
768
+
769
+ // Initialize drawingData
770
+ $this->_drawingData = '';
771
+
772
+ // Initialize objs
773
+ $this->_objs = array();
774
+
775
+ // Initialize shared formula parts
776
+ $this->_sharedFormulaParts = array();
777
+
778
+ // Initialize shared formulas
779
+ $this->_sharedFormulas = array();
780
+
781
+ // Initialize text objs
782
+ $this->_textObjects = array();
783
+
784
+ // Initialize cell annotations
785
+ $this->_cellNotes = array();
786
+ $this->textObjRef = -1;
787
+
788
+ while ($this->_pos <= $this->_dataSize - 4) {
789
+ $code = self::_GetInt2d($this->_data, $this->_pos);
790
+
791
+ switch ($code) {
792
+ case self::XLS_Type_BOF: $this->_readBof(); break;
793
+ case self::XLS_Type_PRINTGRIDLINES: $this->_readPrintGridlines(); break;
794
+ case self::XLS_Type_DEFAULTROWHEIGHT: $this->_readDefaultRowHeight(); break;
795
+ case self::XLS_Type_SHEETPR: $this->_readSheetPr(); break;
796
+ case self::XLS_Type_HORIZONTALPAGEBREAKS: $this->_readHorizontalPageBreaks(); break;
797
+ case self::XLS_Type_VERTICALPAGEBREAKS: $this->_readVerticalPageBreaks(); break;
798
+ case self::XLS_Type_HEADER: $this->_readHeader(); break;
799
+ case self::XLS_Type_FOOTER: $this->_readFooter(); break;
800
+ case self::XLS_Type_HCENTER: $this->_readHcenter(); break;
801
+ case self::XLS_Type_VCENTER: $this->_readVcenter(); break;
802
+ case self::XLS_Type_LEFTMARGIN: $this->_readLeftMargin(); break;
803
+ case self::XLS_Type_RIGHTMARGIN: $this->_readRightMargin(); break;
804
+ case self::XLS_Type_TOPMARGIN: $this->_readTopMargin(); break;
805
+ case self::XLS_Type_BOTTOMMARGIN: $this->_readBottomMargin(); break;
806
+ case self::XLS_Type_PAGESETUP: $this->_readPageSetup(); break;
807
+ case self::XLS_Type_PROTECT: $this->_readProtect(); break;
808
+ case self::XLS_Type_SCENPROTECT: $this->_readScenProtect(); break;
809
+ case self::XLS_Type_OBJECTPROTECT: $this->_readObjectProtect(); break;
810
+ case self::XLS_Type_PASSWORD: $this->_readPassword(); break;
811
+ case self::XLS_Type_DEFCOLWIDTH: $this->_readDefColWidth(); break;
812
+ case self::XLS_Type_COLINFO: $this->_readColInfo(); break;
813
+ case self::XLS_Type_DIMENSION: $this->_readDefault(); break;
814
+ case self::XLS_Type_ROW: $this->_readRow(); break;
815
+ case self::XLS_Type_DBCELL: $this->_readDefault(); break;
816
+ case self::XLS_Type_RK: $this->_readRk(); break;
817
+ case self::XLS_Type_LABELSST: $this->_readLabelSst(); break;
818
+ case self::XLS_Type_MULRK: $this->_readMulRk(); break;
819
+ case self::XLS_Type_NUMBER: $this->_readNumber(); break;
820
+ case self::XLS_Type_FORMULA: $this->_readFormula(); break;
821
+ case self::XLS_Type_SHAREDFMLA: $this->_readSharedFmla(); break;
822
+ case self::XLS_Type_BOOLERR: $this->_readBoolErr(); break;
823
+ case self::XLS_Type_MULBLANK: $this->_readMulBlank(); break;
824
+ case self::XLS_Type_LABEL: $this->_readLabel(); break;
825
+ case self::XLS_Type_BLANK: $this->_readBlank(); break;
826
+ case self::XLS_Type_MSODRAWING: $this->_readMsoDrawing(); break;
827
+ case self::XLS_Type_OBJ: $this->_readObj(); break;
828
+ case self::XLS_Type_WINDOW2: $this->_readWindow2(); break;
829
+ case self::XLS_Type_PAGELAYOUTVIEW: $this->_readPageLayoutView(); break;
830
+ case self::XLS_Type_SCL: $this->_readScl(); break;
831
+ case self::XLS_Type_PANE: $this->_readPane(); break;
832
+ case self::XLS_Type_SELECTION: $this->_readSelection(); break;
833
+ case self::XLS_Type_MERGEDCELLS: $this->_readMergedCells(); break;
834
+ case self::XLS_Type_HYPERLINK: $this->_readHyperLink(); break;
835
+ case self::XLS_Type_DATAVALIDATIONS: $this->_readDataValidations(); break;
836
+ case self::XLS_Type_DATAVALIDATION: $this->_readDataValidation(); break;
837
+ case self::XLS_Type_SHEETLAYOUT: $this->_readSheetLayout(); break;
838
+ case self::XLS_Type_SHEETPROTECTION: $this->_readSheetProtection(); break;
839
+ case self::XLS_Type_RANGEPROTECTION: $this->_readRangeProtection(); break;
840
+ case self::XLS_Type_NOTE: $this->_readNote(); break;
841
+ //case self::XLS_Type_IMDATA: $this->_readImData(); break;
842
+ case self::XLS_Type_TXO: $this->_readTextObject(); break;
843
+ case self::XLS_Type_CONTINUE: $this->_readContinue(); break;
844
+ case self::XLS_Type_EOF: $this->_readDefault(); break 2;
845
+ default: $this->_readDefault(); break;
846
+ }
847
+
848
+ }
849
+
850
+ // treat MSODRAWING records, sheet-level Escher
851
+ if (!$this->_readDataOnly && $this->_drawingData) {
852
+ $escherWorksheet = new PHPExcel_Shared_Escher();
853
+ $reader = new PHPExcel_Reader_Excel5_Escher($escherWorksheet);
854
+ $escherWorksheet = $reader->load($this->_drawingData);
855
+
856
+ // debug Escher stream
857
+ //$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
858
+ //$debug->load($this->_drawingData);
859
+
860
+ // get all spContainers in one long array, so they can be mapped to OBJ records
861
+ $allSpContainers = $escherWorksheet->getDgContainer()->getSpgrContainer()->getAllSpContainers();
862
+ }
863
+
864
+ // treat OBJ records
865
+ foreach ($this->_objs as $n => $obj) {
866
+ // echo '<hr /><b>Object</b> reference is ',$n,'<br />';
867
+ // var_dump($obj);
868
+ // echo '<br />';
869
+
870
+ // the first shape container never has a corresponding OBJ record, hence $n + 1
871
+ if (isset($allSpContainers[$n + 1]) && is_object($allSpContainers[$n + 1])) {
872
+ $spContainer = $allSpContainers[$n + 1];
873
+
874
+ // we skip all spContainers that are a part of a group shape since we cannot yet handle those
875
+ if ($spContainer->getNestingLevel() > 1) {
876
+ continue;
877
+ }
878
+
879
+ // calculate the width and height of the shape
880
+ list($startColumn, $startRow) = PHPExcel_Cell::coordinateFromString($spContainer->getStartCoordinates());
881
+ list($endColumn, $endRow) = PHPExcel_Cell::coordinateFromString($spContainer->getEndCoordinates());
882
+
883
+ $startOffsetX = $spContainer->getStartOffsetX();
884
+ $startOffsetY = $spContainer->getStartOffsetY();
885
+ $endOffsetX = $spContainer->getEndOffsetX();
886
+ $endOffsetY = $spContainer->getEndOffsetY();
887
+
888
+ $width = PHPExcel_Shared_Excel5::getDistanceX($this->_phpSheet, $startColumn, $startOffsetX, $endColumn, $endOffsetX);
889
+ $height = PHPExcel_Shared_Excel5::getDistanceY($this->_phpSheet, $startRow, $startOffsetY, $endRow, $endOffsetY);
890
+
891
+ // calculate offsetX and offsetY of the shape
892
+ $offsetX = $startOffsetX * PHPExcel_Shared_Excel5::sizeCol($this->_phpSheet, $startColumn) / 1024;
893
+ $offsetY = $startOffsetY * PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet, $startRow) / 256;
894
+
895
+ switch ($obj['otObjType']) {
896
+ case 0x19:
897
+ // Note
898
+ // echo 'Cell Annotation Object<br />';
899
+ // echo 'Object ID is ',$obj['idObjID'],'<br />';
900
+ //
901
+ if (isset($this->_cellNotes[$obj['idObjID']])) {
902
+ $cellNote = $this->_cellNotes[$obj['idObjID']];
903
+
904
+ if (isset($this->_textObjects[$obj['idObjID']])) {
905
+ $textObject = $this->_textObjects[$obj['idObjID']];
906
+ $this->_cellNotes[$obj['idObjID']]['objTextData'] = $textObject;
907
+ }
908
+ }
909
+ break;
910
+
911
+ case 0x08:
912
+ // echo 'Picture Object<br />';
913
+ // picture
914
+
915
+ // get index to BSE entry (1-based)
916
+ $BSEindex = $spContainer->getOPT(0x0104);
917
+ $BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection();
918
+ $BSE = $BSECollection[$BSEindex - 1];
919
+ $blipType = $BSE->getBlipType();
920
+
921
+ // need check because some blip types are not supported by Escher reader such as EMF
922
+ if ($blip = $BSE->getBlip()) {
923
+ $ih = imagecreatefromstring($blip->getData());
924
+ $drawing = new PHPExcel_Worksheet_MemoryDrawing();
925
+ $drawing->setImageResource($ih);
926
+
927
+ // width, height, offsetX, offsetY
928
+ $drawing->setResizeProportional(false);
929
+ $drawing->setWidth($width);
930
+ $drawing->setHeight($height);
931
+ $drawing->setOffsetX($offsetX);
932
+ $drawing->setOffsetY($offsetY);
933
+
934
+ switch ($blipType) {
935
+ case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG:
936
+ $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_JPEG);
937
+ $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG);
938
+ break;
939
+
940
+ case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG:
941
+ $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG);
942
+ $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG);
943
+ break;
944
+ }
945
+
946
+ $drawing->setWorksheet($this->_phpSheet);
947
+ $drawing->setCoordinates($spContainer->getStartCoordinates());
948
+ }
949
+
950
+ break;
951
+
952
+ default:
953
+ // other object type
954
+ break;
955
+
956
+ }
957
+ }
958
+ }
959
+
960
+ // treat SHAREDFMLA records
961
+ if ($this->_version == self::XLS_BIFF8) {
962
+ foreach ($this->_sharedFormulaParts as $cell => $baseCell) {
963
+ list($column, $row) = PHPExcel_Cell::coordinateFromString($cell);
964
+ if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle()) ) {
965
+ $formula = $this->_getFormulaFromStructure($this->_sharedFormulas[$baseCell], $cell);
966
+ $this->_phpSheet->getCell($cell)->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
967
+ }
968
+ }
969
+ }
970
+
971
+ if (!empty($this->_cellNotes)) {
972
+ foreach($this->_cellNotes as $note => $noteDetails) {
973
+ if (!isset($noteDetails['objTextData'])) {
974
+ if (isset($this->_textObjects[$note])) {
975
+ $textObject = $this->_textObjects[$note];
976
+ $noteDetails['objTextData'] = $textObject;
977
+ } else {
978
+ $noteDetails['objTextData']['text'] = '';
979
+ }
980
+ }
981
+ // echo '<b>Cell annotation ',$note,'</b><br />';
982
+ // var_dump($noteDetails);
983
+ // echo '<br />';
984
+ $cellAddress = str_replace('$','',$noteDetails['cellRef']);
985
+ $this->_phpSheet->getComment( $cellAddress )
986
+ ->setAuthor( $noteDetails['author'] )
987
+ ->setText($this->_parseRichText($noteDetails['objTextData']['text']) );
988
+ }
989
+ }
990
+ }
991
+
992
+ // add the named ranges (defined names)
993
+ foreach ($this->_definedname as $definedName) {
994
+ if ($definedName['isBuiltInName']) {
995
+ switch ($definedName['name']) {
996
+
997
+ case pack('C', 0x06):
998
+ // print area
999
+ // in general, formula looks like this: Foo!$C$7:$J$66,Bar!$A$1:$IV$2
1000
+ $ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
1001
+
1002
+ $extractedRanges = array();
1003
+ foreach ($ranges as $range) {
1004
+ // $range should look like one of these
1005
+ // Foo!$C$7:$J$66
1006
+ // Bar!$A$1:$IV$2
1007
+
1008
+ $explodes = explode('!', $range); // FIXME: what if sheetname contains exclamation mark?
1009
+ $sheetName = trim($explodes[0], "'");
1010
+
1011
+ if (count($explodes) == 2) {
1012
+ if (strpos($explodes[1], ':') === FALSE) {
1013
+ $explodes[1] = $explodes[1] . ':' . $explodes[1];
1014
+ }
1015
+ $extractedRanges[] = str_replace('$', '', $explodes[1]); // C7:J66
1016
+ }
1017
+ }
1018
+ if ($docSheet = $this->_phpExcel->getSheetByName($sheetName)) {
1019
+ $docSheet->getPageSetup()->setPrintArea(implode(',', $extractedRanges)); // C7:J66,A1:IV2
1020
+ }
1021
+ break;
1022
+
1023
+ case pack('C', 0x07):
1024
+ // print titles (repeating rows)
1025
+ // Assuming BIFF8, there are 3 cases
1026
+ // 1. repeating rows
1027
+ // formula looks like this: Sheet!$A$1:$IV$2
1028
+ // rows 1-2 repeat
1029
+ // 2. repeating columns
1030
+ // formula looks like this: Sheet!$A$1:$B$65536
1031
+ // columns A-B repeat
1032
+ // 3. both repeating rows and repeating columns
1033
+ // formula looks like this: Sheet!$A$1:$B$65536,Sheet!$A$1:$IV$2
1034
+
1035
+ $ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
1036
+
1037
+ foreach ($ranges as $range) {
1038
+ // $range should look like this one of these
1039
+ // Sheet!$A$1:$B$65536
1040
+ // Sheet!$A$1:$IV$2
1041
+
1042
+ $explodes = explode('!', $range);
1043
+
1044
+ if (count($explodes) == 2) {
1045
+ if ($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) {
1046
+
1047
+ $extractedRange = $explodes[1];
1048
+ $extractedRange = str_replace('$', '', $extractedRange);
1049
+
1050
+ $coordinateStrings = explode(':', $extractedRange);
1051
+ if (count($coordinateStrings) == 2) {
1052
+ list($firstColumn, $firstRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[0]);
1053
+ list($lastColumn, $lastRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[1]);
1054
+
1055
+ if ($firstColumn == 'A' and $lastColumn == 'IV') {
1056
+ // then we have repeating rows
1057
+ $docSheet->getPageSetup()->setRowsToRepeatAtTop(array($firstRow, $lastRow));
1058
+ } elseif ($firstRow == 1 and $lastRow == 65536) {
1059
+ // then we have repeating columns
1060
+ $docSheet->getPageSetup()->setColumnsToRepeatAtLeft(array($firstColumn, $lastColumn));
1061
+ }
1062
+ }
1063
+ }
1064
+ }
1065
+ }
1066
+ break;
1067
+
1068
+ }
1069
+ } else {
1070
+ // Extract range
1071
+ $explodes = explode('!', $definedName['formula']);
1072
+
1073
+ if (count($explodes) == 2) {
1074
+ if (($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) ||
1075
+ ($docSheet = $this->_phpExcel->getSheetByName(trim($explodes[0],"'")))) {
1076
+ $extractedRange = $explodes[1];
1077
+ $extractedRange = str_replace('$', '', $extractedRange);
1078
+
1079
+ $localOnly = ($definedName['scope'] == 0) ? false : true;
1080
+
1081
+ $scope = ($definedName['scope'] == 0) ?
1082
+ null : $this->_phpExcel->getSheetByName($this->_sheets[$definedName['scope'] - 1]['name']);
1083
+
1084
+ $this->_phpExcel->addNamedRange( new PHPExcel_NamedRange((string)$definedName['name'], $docSheet, $extractedRange, $localOnly, $scope) );
1085
+ }
1086
+ } else {
1087
+ // Named Value
1088
+ // TODO Provide support for named values
1089
+ }
1090
+ }
1091
+ }
1092
+ $this->_data = null;
1093
+
1094
+ return $this->_phpExcel;
1095
+ }
1096
+
1097
+ /**
1098
+ * Read record data from stream, decrypting as required
1099
+ *
1100
+ * @param string $data Data stream to read from
1101
+ * @param int $pos Position to start reading from
1102
+ * @param int $length Record data length
1103
+ *
1104
+ * @return string Record data
1105
+ */
1106
+ private function _readRecordData($data, $pos, $len)
1107
+ {
1108
+ $data = substr($data, $pos, $len);
1109
+
1110
+ // File not encrypted, or record before encryption start point
1111
+ if ($this->_encryption == self::MS_BIFF_CRYPTO_NONE || $pos < $this->_encryptionStartPos) {
1112
+ return $data;
1113
+ }
1114
+
1115
+ $recordData = '';
1116
+ if ($this->_encryption == self::MS_BIFF_CRYPTO_RC4) {
1117
+
1118
+ $oldBlock = floor($this->_rc4Pos / self::REKEY_BLOCK);
1119
+ $block = floor($pos / self::REKEY_BLOCK);
1120
+ $endBlock = floor(($pos + $len) / self::REKEY_BLOCK);
1121
+
1122
+ // Spin an RC4 decryptor to the right spot. If we have a decryptor sitting
1123
+ // at a point earlier in the current block, re-use it as we can save some time.
1124
+ if ($block != $oldBlock || $pos < $this->_rc4Pos || !$this->_rc4Key) {
1125
+ $this->_rc4Key = $this->_makeKey($block, $this->_md5Ctxt);
1126
+ $step = $pos % self::REKEY_BLOCK;
1127
+ } else {
1128
+ $step = $pos - $this->_rc4Pos;
1129
+ }
1130
+ $this->_rc4Key->RC4(str_repeat("\0", $step));
1131
+
1132
+ // Decrypt record data (re-keying at the end of every block)
1133
+ while ($block != $endBlock) {
1134
+ $step = self::REKEY_BLOCK - ($pos % self::REKEY_BLOCK);
1135
+ $recordData .= $this->_rc4Key->RC4(substr($data, 0, $step));
1136
+ $data = substr($data, $step);
1137
+ $pos += $step;
1138
+ $len -= $step;
1139
+ $block++;
1140
+ $this->_rc4Key = $this->_makeKey($block, $this->_md5Ctxt);
1141
+ }
1142
+ $recordData .= $this->_rc4Key->RC4(substr($data, 0, $len));
1143
+
1144
+ // Keep track of the position of this decryptor.
1145
+ // We'll try and re-use it later if we can to speed things up
1146
+ $this->_rc4Pos = $pos + $len;
1147
+
1148
+ } elseif ($this->_encryption == self::MS_BIFF_CRYPTO_XOR) {
1149
+ throw new PHPExcel_Reader_Exception('XOr encryption not supported');
1150
+ }
1151
+ return $recordData;
1152
+ }
1153
+
1154
+ /**
1155
+ * Use OLE reader to extract the relevant data streams from the OLE file
1156
+ *
1157
+ * @param string $pFilename
1158
+ */
1159
+ private function _loadOLE($pFilename)
1160
+ {
1161
+ // OLE reader
1162
+ $ole = new PHPExcel_Shared_OLERead();
1163
+
1164
+ // get excel data,
1165
+ $res = $ole->read($pFilename);
1166
+ // Get workbook data: workbook stream + sheet streams
1167
+ $this->_data = $ole->getStream($ole->wrkbook);
1168
+
1169
+ // Get summary information data
1170
+ $this->_summaryInformation = $ole->getStream($ole->summaryInformation);
1171
+
1172
+ // Get additional document summary information data
1173
+ $this->_documentSummaryInformation = $ole->getStream($ole->documentSummaryInformation);
1174
+
1175
+ // Get user-defined property data
1176
+ // $this->_userDefinedProperties = $ole->getUserDefinedProperties();
1177
+ }
1178
+
1179
+
1180
+ /**
1181
+ * Read summary information
1182
+ */
1183
+ private function _readSummaryInformation()
1184
+ {
1185
+ if (!isset($this->_summaryInformation)) {
1186
+ return;
1187
+ }
1188
+
1189
+ // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
1190
+ // offset: 2; size: 2;
1191
+ // offset: 4; size: 2; OS version
1192
+ // offset: 6; size: 2; OS indicator
1193
+ // offset: 8; size: 16
1194
+ // offset: 24; size: 4; section count
1195
+ $secCount = self::_GetInt4d($this->_summaryInformation, 24);
1196
+
1197
+ // offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9
1198
+ // offset: 44; size: 4
1199
+ $secOffset = self::_GetInt4d($this->_summaryInformation, 44);
1200
+
1201
+ // section header
1202
+ // offset: $secOffset; size: 4; section length
1203
+ $secLength = self::_GetInt4d($this->_summaryInformation, $secOffset);
1204
+
1205
+ // offset: $secOffset+4; size: 4; property count
1206
+ $countProperties = self::_GetInt4d($this->_summaryInformation, $secOffset+4);
1207
+
1208
+ // initialize code page (used to resolve string values)
1209
+ $codePage = 'CP1252';
1210
+
1211
+ // offset: ($secOffset+8); size: var
1212
+ // loop through property decarations and properties
1213
+ for ($i = 0; $i < $countProperties; ++$i) {
1214
+
1215
+ // offset: ($secOffset+8) + (8 * $i); size: 4; property ID
1216
+ $id = self::_GetInt4d($this->_summaryInformation, ($secOffset+8) + (8 * $i));
1217
+
1218
+ // Use value of property id as appropriate
1219
+ // offset: ($secOffset+12) + (8 * $i); size: 4; offset from beginning of section (48)
1220
+ $offset = self::_GetInt4d($this->_summaryInformation, ($secOffset+12) + (8 * $i));
1221
+
1222
+ $type = self::_GetInt4d($this->_summaryInformation, $secOffset + $offset);
1223
+
1224
+ // initialize property value
1225
+ $value = null;
1226
+
1227
+ // extract property value based on property type
1228
+ switch ($type) {
1229
+ case 0x02: // 2 byte signed integer
1230
+ $value = self::_GetInt2d($this->_summaryInformation, $secOffset + 4 + $offset);
1231
+ break;
1232
+
1233
+ case 0x03: // 4 byte signed integer
1234
+ $value = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
1235
+ break;
1236
+
1237
+ case 0x13: // 4 byte unsigned integer
1238
+ // not needed yet, fix later if necessary
1239
+ break;
1240
+
1241
+ case 0x1E: // null-terminated string prepended by dword string length
1242
+ $byteLength = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
1243
+ $value = substr($this->_summaryInformation, $secOffset + 8 + $offset, $byteLength);
1244
+ $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
1245
+ $value = rtrim($value);
1246
+ break;
1247
+
1248
+ case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
1249
+ // PHP-time
1250
+ $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_summaryInformation, $secOffset + 4 + $offset, 8));
1251
+ break;
1252
+
1253
+ case 0x47: // Clipboard format
1254
+ // not needed yet, fix later if necessary
1255
+ break;
1256
+ }
1257
+
1258
+ switch ($id) {
1259
+ case 0x01: // Code Page
1260
+ $codePage = PHPExcel_Shared_CodePage::NumberToName($value);
1261
+ break;
1262
+
1263
+ case 0x02: // Title
1264
+ $this->_phpExcel->getProperties()->setTitle($value);
1265
+ break;
1266
+
1267
+ case 0x03: // Subject
1268
+ $this->_phpExcel->getProperties()->setSubject($value);
1269
+ break;
1270
+
1271
+ case 0x04: // Author (Creator)
1272
+ $this->_phpExcel->getProperties()->setCreator($value);
1273
+ break;
1274
+
1275
+ case 0x05: // Keywords
1276
+ $this->_phpExcel->getProperties()->setKeywords($value);
1277
+ break;
1278
+
1279
+ case 0x06: // Comments (Description)
1280
+ $this->_phpExcel->getProperties()->setDescription($value);
1281
+ break;
1282
+
1283
+ case 0x07: // Template
1284
+ // Not supported by PHPExcel
1285
+ break;
1286
+
1287
+ case 0x08: // Last Saved By (LastModifiedBy)
1288
+ $this->_phpExcel->getProperties()->setLastModifiedBy($value);
1289
+ break;
1290
+
1291
+ case 0x09: // Revision
1292
+ // Not supported by PHPExcel
1293
+ break;
1294
+
1295
+ case 0x0A: // Total Editing Time
1296
+ // Not supported by PHPExcel
1297
+ break;
1298
+
1299
+ case 0x0B: // Last Printed
1300
+ // Not supported by PHPExcel
1301
+ break;
1302
+
1303
+ case 0x0C: // Created Date/Time
1304
+ $this->_phpExcel->getProperties()->setCreated($value);
1305
+ break;
1306
+
1307
+ case 0x0D: // Modified Date/Time
1308
+ $this->_phpExcel->getProperties()->setModified($value);
1309
+ break;
1310
+
1311
+ case 0x0E: // Number of Pages
1312
+ // Not supported by PHPExcel
1313
+ break;
1314
+
1315
+ case 0x0F: // Number of Words
1316
+ // Not supported by PHPExcel
1317
+ break;
1318
+
1319
+ case 0x10: // Number of Characters
1320
+ // Not supported by PHPExcel
1321
+ break;
1322
+
1323
+ case 0x11: // Thumbnail
1324
+ // Not supported by PHPExcel
1325
+ break;
1326
+
1327
+ case 0x12: // Name of creating application
1328
+ // Not supported by PHPExcel
1329
+ break;
1330
+
1331
+ case 0x13: // Security
1332
+ // Not supported by PHPExcel
1333
+ break;
1334
+
1335
+ }
1336
+ }
1337
+ }
1338
+
1339
+
1340
+ /**
1341
+ * Read additional document summary information
1342
+ */
1343
+ private function _readDocumentSummaryInformation()
1344
+ {
1345
+ if (!isset($this->_documentSummaryInformation)) {
1346
+ return;
1347
+ }
1348
+
1349
+ // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
1350
+ // offset: 2; size: 2;
1351
+ // offset: 4; size: 2; OS version
1352
+ // offset: 6; size: 2; OS indicator
1353
+ // offset: 8; size: 16
1354
+ // offset: 24; size: 4; section count
1355
+ $secCount = self::_GetInt4d($this->_documentSummaryInformation, 24);
1356
+ // echo '$secCount = ',$secCount,'<br />';
1357
+
1358
+ // offset: 28; size: 16; first section's class id: 02 d5 cd d5 9c 2e 1b 10 93 97 08 00 2b 2c f9 ae
1359
+ // offset: 44; size: 4; first section offset
1360
+ $secOffset = self::_GetInt4d($this->_documentSummaryInformation, 44);
1361
+ // echo '$secOffset = ',$secOffset,'<br />';
1362
+
1363
+ // section header
1364
+ // offset: $secOffset; size: 4; section length
1365
+ $secLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset);
1366
+ // echo '$secLength = ',$secLength,'<br />';
1367
+
1368
+ // offset: $secOffset+4; size: 4; property count
1369
+ $countProperties = self::_GetInt4d($this->_documentSummaryInformation, $secOffset+4);
1370
+ // echo '$countProperties = ',$countProperties,'<br />';
1371
+
1372
+ // initialize code page (used to resolve string values)
1373
+ $codePage = 'CP1252';
1374
+
1375
+ // offset: ($secOffset+8); size: var
1376
+ // loop through property decarations and properties
1377
+ for ($i = 0; $i < $countProperties; ++$i) {
1378
+ // echo 'Property ',$i,'<br />';
1379
+ // offset: ($secOffset+8) + (8 * $i); size: 4; property ID
1380
+ $id = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+8) + (8 * $i));
1381
+ // echo 'ID is ',$id,'<br />';
1382
+
1383
+ // Use value of property id as appropriate
1384
+ // offset: 60 + 8 * $i; size: 4; offset from beginning of section (48)
1385
+ $offset = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+12) + (8 * $i));
1386
+
1387
+ $type = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + $offset);
1388
+ // echo 'Type is ',$type,', ';
1389
+
1390
+ // initialize property value
1391
+ $value = null;
1392
+
1393
+ // extract property value based on property type
1394
+ switch ($type) {
1395
+ case 0x02: // 2 byte signed integer
1396
+ $value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1397
+ break;
1398
+
1399
+ case 0x03: // 4 byte signed integer
1400
+ $value = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1401
+ break;
1402
+
1403
+ case 0x0B: // Boolean
1404
+ $value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1405
+ $value = ($value == 0 ? false : true);
1406
+ break;
1407
+
1408
+ case 0x13: // 4 byte unsigned integer
1409
+ // not needed yet, fix later if necessary
1410
+ break;
1411
+
1412
+ case 0x1E: // null-terminated string prepended by dword string length
1413
+ $byteLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1414
+ $value = substr($this->_documentSummaryInformation, $secOffset + 8 + $offset, $byteLength);
1415
+ $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
1416
+ $value = rtrim($value);
1417
+ break;
1418
+
1419
+ case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
1420
+ // PHP-Time
1421
+ $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_documentSummaryInformation, $secOffset + 4 + $offset, 8));
1422
+ break;
1423
+
1424
+ case 0x47: // Clipboard format
1425
+ // not needed yet, fix later if necessary
1426
+ break;
1427
+ }
1428
+
1429
+ switch ($id) {
1430
+ case 0x01: // Code Page
1431
+ $codePage = PHPExcel_Shared_CodePage::NumberToName($value);
1432
+ break;
1433
+
1434
+ case 0x02: // Category
1435
+ $this->_phpExcel->getProperties()->setCategory($value);
1436
+ break;
1437
+
1438
+ case 0x03: // Presentation Target
1439
+ // Not supported by PHPExcel
1440
+ break;
1441
+
1442
+ case 0x04: // Bytes
1443
+ // Not supported by PHPExcel
1444
+ break;
1445
+
1446
+ case 0x05: // Lines
1447
+ // Not supported by PHPExcel
1448
+ break;
1449
+
1450
+ case 0x06: // Paragraphs
1451
+ // Not supported by PHPExcel
1452
+ break;
1453
+
1454
+ case 0x07: // Slides
1455
+ // Not supported by PHPExcel
1456
+ break;
1457
+
1458
+ case 0x08: // Notes
1459
+ // Not supported by PHPExcel
1460
+ break;
1461
+
1462
+ case 0x09: // Hidden Slides
1463
+ // Not supported by PHPExcel
1464
+ break;
1465
+
1466
+ case 0x0A: // MM Clips
1467
+ // Not supported by PHPExcel
1468
+ break;
1469
+
1470
+ case 0x0B: // Scale Crop
1471
+ // Not supported by PHPExcel
1472
+ break;
1473
+
1474
+ case 0x0C: // Heading Pairs
1475
+ // Not supported by PHPExcel
1476
+ break;
1477
+
1478
+ case 0x0D: // Titles of Parts
1479
+ // Not supported by PHPExcel
1480
+ break;
1481
+
1482
+ case 0x0E: // Manager
1483
+ $this->_phpExcel->getProperties()->setManager($value);
1484
+ break;
1485
+
1486
+ case 0x0F: // Company
1487
+ $this->_phpExcel->getProperties()->setCompany($value);
1488
+ break;
1489
+
1490
+ case 0x10: // Links up-to-date
1491
+ // Not supported by PHPExcel
1492
+ break;
1493
+
1494
+ }
1495
+ }
1496
+ }
1497
+
1498
+
1499
+ /**
1500
+ * Reads a general type of BIFF record. Does nothing except for moving stream pointer forward to next record.
1501
+ */
1502
+ private function _readDefault()
1503
+ {
1504
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1505
+ // $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1506
+
1507
+ // move stream pointer to next record
1508
+ $this->_pos += 4 + $length;
1509
+ }
1510
+
1511
+
1512
+ /**
1513
+ * The NOTE record specifies a comment associated with a particular cell. In Excel 95 (BIFF7) and earlier versions,
1514
+ * this record stores a note (cell note). This feature was significantly enhanced in Excel 97.
1515
+ */
1516
+ private function _readNote()
1517
+ {
1518
+ // echo '<b>Read Cell Annotation</b><br />';
1519
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1520
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1521
+
1522
+ // move stream pointer to next record
1523
+ $this->_pos += 4 + $length;
1524
+
1525
+ if ($this->_readDataOnly) {
1526
+ return;
1527
+ }
1528
+
1529
+ $cellAddress = $this->_readBIFF8CellAddress(substr($recordData, 0, 4));
1530
+ if ($this->_version == self::XLS_BIFF8) {
1531
+ $noteObjID = self::_GetInt2d($recordData, 6);
1532
+ $noteAuthor = self::_readUnicodeStringLong(substr($recordData, 8));
1533
+ $noteAuthor = $noteAuthor['value'];
1534
+ // echo 'Note Address=',$cellAddress,'<br />';
1535
+ // echo 'Note Object ID=',$noteObjID,'<br />';
1536
+ // echo 'Note Author=',$noteAuthor,'<hr />';
1537
+ //
1538
+ $this->_cellNotes[$noteObjID] = array('cellRef' => $cellAddress,
1539
+ 'objectID' => $noteObjID,
1540
+ 'author' => $noteAuthor
1541
+ );
1542
+ } else {
1543
+ $extension = false;
1544
+ if ($cellAddress == '$B$65536') {
1545
+ // If the address row is -1 and the column is 0, (which translates as $B$65536) then this is a continuation
1546
+ // note from the previous cell annotation. We're not yet handling this, so annotations longer than the
1547
+ // max 2048 bytes will probably throw a wobbly.
1548
+ $row = self::_GetInt2d($recordData, 0);
1549
+ $extension = true;
1550
+ $cellAddress = array_pop(array_keys($this->_phpSheet->getComments()));
1551
+ }
1552
+ // echo 'Note Address=',$cellAddress,'<br />';
1553
+
1554
+ $cellAddress = str_replace('$','',$cellAddress);
1555
+ $noteLength = self::_GetInt2d($recordData, 4);
1556
+ $noteText = trim(substr($recordData, 6));
1557
+ // echo 'Note Length=',$noteLength,'<br />';
1558
+ // echo 'Note Text=',$noteText,'<br />';
1559
+
1560
+ if ($extension) {
1561
+ // Concatenate this extension with the currently set comment for the cell
1562
+ $comment = $this->_phpSheet->getComment( $cellAddress );
1563
+ $commentText = $comment->getText()->getPlainText();
1564
+ $comment->setText($this->_parseRichText($commentText.$noteText) );
1565
+ } else {
1566
+ // Set comment for the cell
1567
+ $this->_phpSheet->getComment( $cellAddress )
1568
+ // ->setAuthor( $author )
1569
+ ->setText($this->_parseRichText($noteText) );
1570
+ }
1571
+ }
1572
+
1573
+ }
1574
+
1575
+
1576
+ /**
1577
+ * The TEXT Object record contains the text associated with a cell annotation.
1578
+ */
1579
+ private function _readTextObject()
1580
+ {
1581
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1582
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1583
+
1584
+ // move stream pointer to next record
1585
+ $this->_pos += 4 + $length;
1586
+
1587
+ if ($this->_readDataOnly) {
1588
+ return;
1589
+ }
1590
+
1591
+ // recordData consists of an array of subrecords looking like this:
1592
+ // grbit: 2 bytes; Option Flags
1593
+ // rot: 2 bytes; rotation
1594
+ // cchText: 2 bytes; length of the text (in the first continue record)
1595
+ // cbRuns: 2 bytes; length of the formatting (in the second continue record)
1596
+ // followed by the continuation records containing the actual text and formatting
1597
+ $grbitOpts = self::_GetInt2d($recordData, 0);
1598
+ $rot = self::_GetInt2d($recordData, 2);
1599
+ $cchText = self::_GetInt2d($recordData, 10);
1600
+ $cbRuns = self::_GetInt2d($recordData, 12);
1601
+ $text = $this->_getSplicedRecordData();
1602
+
1603
+ $this->_textObjects[$this->textObjRef] = array(
1604
+ 'text' => substr($text["recordData"],$text["spliceOffsets"][0]+1,$cchText),
1605
+ 'format' => substr($text["recordData"],$text["spliceOffsets"][1],$cbRuns),
1606
+ 'alignment' => $grbitOpts,
1607
+ 'rotation' => $rot
1608
+ );
1609
+
1610
+ // echo '<b>_readTextObject()</b><br />';
1611
+ // var_dump($this->_textObjects[$this->textObjRef]);
1612
+ // echo '<br />';
1613
+ }
1614
+
1615
+
1616
+ /**
1617
+ * Read BOF
1618
+ */
1619
+ private function _readBof()
1620
+ {
1621
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1622
+ $recordData = substr($this->_data, $this->_pos + 4, $length);
1623
+
1624
+ // move stream pointer to next record
1625
+ $this->_pos += 4 + $length;
1626
+
1627
+ // offset: 2; size: 2; type of the following data
1628
+ $substreamType = self::_GetInt2d($recordData, 2);
1629
+
1630
+ switch ($substreamType) {
1631
+ case self::XLS_WorkbookGlobals:
1632
+ $version = self::_GetInt2d($recordData, 0);
1633
+ if (($version != self::XLS_BIFF8) && ($version != self::XLS_BIFF7)) {
1634
+ throw new PHPExcel_Reader_Exception('Cannot read this Excel file. Version is too old.');
1635
+ }
1636
+ $this->_version = $version;
1637
+ break;
1638
+
1639
+ case self::XLS_Worksheet:
1640
+ // do not use this version information for anything
1641
+ // it is unreliable (OpenOffice doc, 5.8), use only version information from the global stream
1642
+ break;
1643
+
1644
+ default:
1645
+ // substream, e.g. chart
1646
+ // just skip the entire substream
1647
+ do {
1648
+ $code = self::_GetInt2d($this->_data, $this->_pos);
1649
+ $this->_readDefault();
1650
+ } while ($code != self::XLS_Type_EOF && $this->_pos < $this->_dataSize);
1651
+ break;
1652
+ }
1653
+ }
1654
+
1655
+
1656
+ /**
1657
+ * FILEPASS
1658
+ *
1659
+ * This record is part of the File Protection Block. It
1660
+ * contains information about the read/write password of the
1661
+ * file. All record contents following this record will be
1662
+ * encrypted.
1663
+ *
1664
+ * -- "OpenOffice.org's Documentation of the Microsoft
1665
+ * Excel File Format"
1666
+ *
1667
+ * The decryption functions and objects used from here on in
1668
+ * are based on the source of Spreadsheet-ParseExcel:
1669
+ * http://search.cpan.org/~jmcnamara/Spreadsheet-ParseExcel/
1670
+ */
1671
+ private function _readFilepass()
1672
+ {
1673
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1674
+
1675
+ if ($length != 54) {
1676
+ throw new PHPExcel_Reader_Exception('Unexpected file pass record length');
1677
+ }
1678
+
1679
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1680
+
1681
+ // move stream pointer to next record
1682
+ $this->_pos += 4 + $length;
1683
+
1684
+ if (!$this->_verifyPassword(
1685
+ 'VelvetSweatshop',
1686
+ substr($recordData, 6, 16),
1687
+ substr($recordData, 22, 16),
1688
+ substr($recordData, 38, 16),
1689
+ $this->_md5Ctxt
1690
+ )) {
1691
+ throw new PHPExcel_Reader_Exception('Decryption password incorrect');
1692
+ }
1693
+
1694
+ $this->_encryption = self::MS_BIFF_CRYPTO_RC4;
1695
+
1696
+ // Decryption required from the record after next onwards
1697
+ $this->_encryptionStartPos = $this->_pos + self::_GetInt2d($this->_data, $this->_pos + 2);
1698
+ }
1699
+
1700
+ /**
1701
+ * Make an RC4 decryptor for the given block
1702
+ *
1703
+ * @var int $block Block for which to create decrypto
1704
+ * @var string $valContext MD5 context state
1705
+ *
1706
+ * @return PHPExcel_Reader_Excel5_RC4
1707
+ */
1708
+ private function _makeKey($block, $valContext)
1709
+ {
1710
+ $pwarray = str_repeat("\0", 64);
1711
+
1712
+ for ($i = 0; $i < 5; $i++) {
1713
+ $pwarray[$i] = $valContext[$i];
1714
+ }
1715
+
1716
+ $pwarray[5] = chr($block & 0xff);
1717
+ $pwarray[6] = chr(($block >> 8) & 0xff);
1718
+ $pwarray[7] = chr(($block >> 16) & 0xff);
1719
+ $pwarray[8] = chr(($block >> 24) & 0xff);
1720
+
1721
+ $pwarray[9] = "\x80";
1722
+ $pwarray[56] = "\x48";
1723
+
1724
+ $md5 = new PHPExcel_Reader_Excel5_MD5();
1725
+ $md5->add($pwarray);
1726
+
1727
+ $s = $md5->getContext();
1728
+ return new PHPExcel_Reader_Excel5_RC4($s);
1729
+ }
1730
+
1731
+ /**
1732
+ * Verify RC4 file password
1733
+ *
1734
+ * @var string $password Password to check
1735
+ * @var string $docid Document id
1736
+ * @var string $salt_data Salt data
1737
+ * @var string $hashedsalt_data Hashed salt data
1738
+ * @var string &$valContext Set to the MD5 context of the value
1739
+ *
1740
+ * @return bool Success
1741
+ */
1742
+ private function _verifyPassword($password, $docid, $salt_data, $hashedsalt_data, &$valContext)
1743
+ {
1744
+ $pwarray = str_repeat("\0", 64);
1745
+
1746
+ for ($i = 0; $i < strlen($password); $i++) {
1747
+ $o = ord(substr($password, $i, 1));
1748
+ $pwarray[2 * $i] = chr($o & 0xff);
1749
+ $pwarray[2 * $i + 1] = chr(($o >> 8) & 0xff);
1750
+ }
1751
+ $pwarray[2 * $i] = chr(0x80);
1752
+ $pwarray[56] = chr(($i << 4) & 0xff);
1753
+
1754
+ $md5 = new PHPExcel_Reader_Excel5_MD5();
1755
+ $md5->add($pwarray);
1756
+
1757
+ $mdContext1 = $md5->getContext();
1758
+
1759
+ $offset = 0;
1760
+ $keyoffset = 0;
1761
+ $tocopy = 5;
1762
+
1763
+ $md5->reset();
1764
+
1765
+ while ($offset != 16) {
1766
+ if ((64 - $offset) < 5) {
1767
+ $tocopy = 64 - $offset;
1768
+ }
1769
+
1770
+ for ($i = 0; $i <= $tocopy; $i++) {
1771
+ $pwarray[$offset + $i] = $mdContext1[$keyoffset + $i];
1772
+ }
1773
+
1774
+ $offset += $tocopy;
1775
+
1776
+ if ($offset == 64) {
1777
+ $md5->add($pwarray);
1778
+ $keyoffset = $tocopy;
1779
+ $tocopy = 5 - $tocopy;
1780
+ $offset = 0;
1781
+ continue;
1782
+ }
1783
+
1784
+ $keyoffset = 0;
1785
+ $tocopy = 5;
1786
+ for ($i = 0; $i < 16; $i++) {
1787
+ $pwarray[$offset + $i] = $docid[$i];
1788
+ }
1789
+ $offset += 16;
1790
+ }
1791
+
1792
+ $pwarray[16] = "\x80";
1793
+ for ($i = 0; $i < 47; $i++) {
1794
+ $pwarray[17 + $i] = "\0";
1795
+ }
1796
+ $pwarray[56] = "\x80";
1797
+ $pwarray[57] = "\x0a";
1798
+
1799
+ $md5->add($pwarray);
1800
+ $valContext = $md5->getContext();
1801
+
1802
+ $key = $this->_makeKey(0, $valContext);
1803
+
1804
+ $salt = $key->RC4($salt_data);
1805
+ $hashedsalt = $key->RC4($hashedsalt_data);
1806
+
1807
+ $salt .= "\x80" . str_repeat("\0", 47);
1808
+ $salt[56] = "\x80";
1809
+
1810
+ $md5->reset();
1811
+ $md5->add($salt);
1812
+ $mdContext2 = $md5->getContext();
1813
+
1814
+ return $mdContext2 == $hashedsalt;
1815
+ }
1816
+
1817
+ /**
1818
+ * CODEPAGE
1819
+ *
1820
+ * This record stores the text encoding used to write byte
1821
+ * strings, stored as MS Windows code page identifier.
1822
+ *
1823
+ * -- "OpenOffice.org's Documentation of the Microsoft
1824
+ * Excel File Format"
1825
+ */
1826
+ private function _readCodepage()
1827
+ {
1828
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1829
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1830
+
1831
+ // move stream pointer to next record
1832
+ $this->_pos += 4 + $length;
1833
+
1834
+ // offset: 0; size: 2; code page identifier
1835
+ $codepage = self::_GetInt2d($recordData, 0);
1836
+
1837
+ $this->_codepage = PHPExcel_Shared_CodePage::NumberToName($codepage);
1838
+ }
1839
+
1840
+
1841
+ /**
1842
+ * DATEMODE
1843
+ *
1844
+ * This record specifies the base date for displaying date
1845
+ * values. All dates are stored as count of days past this
1846
+ * base date. In BIFF2-BIFF4 this record is part of the
1847
+ * Calculation Settings Block. In BIFF5-BIFF8 it is
1848
+ * stored in the Workbook Globals Substream.
1849
+ *
1850
+ * -- "OpenOffice.org's Documentation of the Microsoft
1851
+ * Excel File Format"
1852
+ */
1853
+ private function _readDateMode()
1854
+ {
1855
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1856
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1857
+
1858
+ // move stream pointer to next record
1859
+ $this->_pos += 4 + $length;
1860
+
1861
+ // offset: 0; size: 2; 0 = base 1900, 1 = base 1904
1862
+ PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900);
1863
+ if (ord($recordData{0}) == 1) {
1864
+ PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_MAC_1904);
1865
+ }
1866
+ }
1867
+
1868
+
1869
+ /**
1870
+ * Read a FONT record
1871
+ */
1872
+ private function _readFont()
1873
+ {
1874
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1875
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1876
+
1877
+ // move stream pointer to next record
1878
+ $this->_pos += 4 + $length;
1879
+
1880
+ if (!$this->_readDataOnly) {
1881
+ $objFont = new PHPExcel_Style_Font();
1882
+
1883
+ // offset: 0; size: 2; height of the font (in twips = 1/20 of a point)
1884
+ $size = self::_GetInt2d($recordData, 0);
1885
+ $objFont->setSize($size / 20);
1886
+
1887
+ // offset: 2; size: 2; option flags
1888
+ // bit: 0; mask 0x0001; bold (redundant in BIFF5-BIFF8)
1889
+ // bit: 1; mask 0x0002; italic
1890
+ $isItalic = (0x0002 & self::_GetInt2d($recordData, 2)) >> 1;
1891
+ if ($isItalic) $objFont->setItalic(true);
1892
+
1893
+ // bit: 2; mask 0x0004; underlined (redundant in BIFF5-BIFF8)
1894
+ // bit: 3; mask 0x0008; strike
1895
+ $isStrike = (0x0008 & self::_GetInt2d($recordData, 2)) >> 3;
1896
+ if ($isStrike) $objFont->setStrikethrough(true);
1897
+
1898
+ // offset: 4; size: 2; colour index
1899
+ $colorIndex = self::_GetInt2d($recordData, 4);
1900
+ $objFont->colorIndex = $colorIndex;
1901
+
1902
+ // offset: 6; size: 2; font weight
1903
+ $weight = self::_GetInt2d($recordData, 6);
1904
+ switch ($weight) {
1905
+ case 0x02BC:
1906
+ $objFont->setBold(true);
1907
+ break;
1908
+ }
1909
+
1910
+ // offset: 8; size: 2; escapement type
1911
+ $escapement = self::_GetInt2d($recordData, 8);
1912
+ switch ($escapement) {
1913
+ case 0x0001:
1914
+ $objFont->setSuperScript(true);
1915
+ break;
1916
+ case 0x0002:
1917
+ $objFont->setSubScript(true);
1918
+ break;
1919
+ }
1920
+
1921
+ // offset: 10; size: 1; underline type
1922
+ $underlineType = ord($recordData{10});
1923
+ switch ($underlineType) {
1924
+ case 0x00:
1925
+ break; // no underline
1926
+ case 0x01:
1927
+ $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
1928
+ break;
1929
+ case 0x02:
1930
+ $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLE);
1931
+ break;
1932
+ case 0x21:
1933
+ $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING);
1934
+ break;
1935
+ case 0x22:
1936
+ $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING);
1937
+ break;
1938
+ }
1939
+
1940
+ // offset: 11; size: 1; font family
1941
+ // offset: 12; size: 1; character set
1942
+ // offset: 13; size: 1; not used
1943
+ // offset: 14; size: var; font name
1944
+ if ($this->_version == self::XLS_BIFF8) {
1945
+ $string = self::_readUnicodeStringShort(substr($recordData, 14));
1946
+ } else {
1947
+ $string = $this->_readByteStringShort(substr($recordData, 14));
1948
+ }
1949
+ $objFont->setName($string['value']);
1950
+
1951
+ $this->_objFonts[] = $objFont;
1952
+ }
1953
+ }
1954
+
1955
+
1956
+ /**
1957
+ * FORMAT
1958
+ *
1959
+ * This record contains information about a number format.
1960
+ * All FORMAT records occur together in a sequential list.
1961
+ *
1962
+ * In BIFF2-BIFF4 other records referencing a FORMAT record
1963
+ * contain a zero-based index into this list. From BIFF5 on
1964
+ * the FORMAT record contains the index itself that will be
1965
+ * used by other records.
1966
+ *
1967
+ * -- "OpenOffice.org's Documentation of the Microsoft
1968
+ * Excel File Format"
1969
+ */
1970
+ private function _readFormat()
1971
+ {
1972
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
1973
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
1974
+
1975
+ // move stream pointer to next record
1976
+ $this->_pos += 4 + $length;
1977
+
1978
+ if (!$this->_readDataOnly) {
1979
+ $indexCode = self::_GetInt2d($recordData, 0);
1980
+
1981
+ if ($this->_version == self::XLS_BIFF8) {
1982
+ $string = self::_readUnicodeStringLong(substr($recordData, 2));
1983
+ } else {
1984
+ // BIFF7
1985
+ $string = $this->_readByteStringShort(substr($recordData, 2));
1986
+ }
1987
+
1988
+ $formatString = $string['value'];
1989
+ $this->_formats[$indexCode] = $formatString;
1990
+ }
1991
+ }
1992
+
1993
+
1994
+ /**
1995
+ * XF - Extended Format
1996
+ *
1997
+ * This record contains formatting information for cells, rows, columns or styles.
1998
+ * According to http://support.microsoft.com/kb/147732 there are always at least 15 cell style XF
1999
+ * and 1 cell XF.
2000
+ * Inspection of Excel files generated by MS Office Excel shows that XF records 0-14 are cell style XF
2001
+ * and XF record 15 is a cell XF
2002
+ * We only read the first cell style XF and skip the remaining cell style XF records
2003
+ * We read all cell XF records.
2004
+ *
2005
+ * -- "OpenOffice.org's Documentation of the Microsoft
2006
+ * Excel File Format"
2007
+ */
2008
+ private function _readXf()
2009
+ {
2010
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2011
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2012
+
2013
+ // move stream pointer to next record
2014
+ $this->_pos += 4 + $length;
2015
+
2016
+ $objStyle = new PHPExcel_Style();
2017
+
2018
+ if (!$this->_readDataOnly) {
2019
+ // offset: 0; size: 2; Index to FONT record
2020
+ if (self::_GetInt2d($recordData, 0) < 4) {
2021
+ $fontIndex = self::_GetInt2d($recordData, 0);
2022
+ } else {
2023
+ // this has to do with that index 4 is omitted in all BIFF versions for some strange reason
2024
+ // check the OpenOffice documentation of the FONT record
2025
+ $fontIndex = self::_GetInt2d($recordData, 0) - 1;
2026
+ }
2027
+ $objStyle->setFont($this->_objFonts[$fontIndex]);
2028
+
2029
+ // offset: 2; size: 2; Index to FORMAT record
2030
+ $numberFormatIndex = self::_GetInt2d($recordData, 2);
2031
+ if (isset($this->_formats[$numberFormatIndex])) {
2032
+ // then we have user-defined format code
2033
+ $numberformat = array('code' => $this->_formats[$numberFormatIndex]);
2034
+ } elseif (($code = PHPExcel_Style_NumberFormat::builtInFormatCode($numberFormatIndex)) !== '') {
2035
+ // then we have built-in format code
2036
+ $numberformat = array('code' => $code);
2037
+ } else {
2038
+ // we set the general format code
2039
+ $numberformat = array('code' => 'General');
2040
+ }
2041
+ $objStyle->getNumberFormat()->setFormatCode($numberformat['code']);
2042
+
2043
+ // offset: 4; size: 2; XF type, cell protection, and parent style XF
2044
+ // bit 2-0; mask 0x0007; XF_TYPE_PROT
2045
+ $xfTypeProt = self::_GetInt2d($recordData, 4);
2046
+ // bit 0; mask 0x01; 1 = cell is locked
2047
+ $isLocked = (0x01 & $xfTypeProt) >> 0;
2048
+ $objStyle->getProtection()->setLocked($isLocked ?
2049
+ PHPExcel_Style_Protection::PROTECTION_INHERIT : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
2050
+
2051
+ // bit 1; mask 0x02; 1 = Formula is hidden
2052
+ $isHidden = (0x02 & $xfTypeProt) >> 1;
2053
+ $objStyle->getProtection()->setHidden($isHidden ?
2054
+ PHPExcel_Style_Protection::PROTECTION_PROTECTED : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
2055
+
2056
+ // bit 2; mask 0x04; 0 = Cell XF, 1 = Cell Style XF
2057
+ $isCellStyleXf = (0x04 & $xfTypeProt) >> 2;
2058
+
2059
+ // offset: 6; size: 1; Alignment and text break
2060
+ // bit 2-0, mask 0x07; horizontal alignment
2061
+ $horAlign = (0x07 & ord($recordData{6})) >> 0;
2062
+ switch ($horAlign) {
2063
+ case 0:
2064
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_GENERAL);
2065
+ break;
2066
+ case 1:
2067
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
2068
+ break;
2069
+ case 2:
2070
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
2071
+ break;
2072
+ case 3:
2073
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
2074
+ break;
2075
+ case 4:
2076
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_FILL);
2077
+ break;
2078
+ case 5:
2079
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY);
2080
+ break;
2081
+ case 6:
2082
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS);
2083
+ break;
2084
+ }
2085
+ // bit 3, mask 0x08; wrap text
2086
+ $wrapText = (0x08 & ord($recordData{6})) >> 3;
2087
+ switch ($wrapText) {
2088
+ case 0:
2089
+ $objStyle->getAlignment()->setWrapText(false);
2090
+ break;
2091
+ case 1:
2092
+ $objStyle->getAlignment()->setWrapText(true);
2093
+ break;
2094
+ }
2095
+ // bit 6-4, mask 0x70; vertical alignment
2096
+ $vertAlign = (0x70 & ord($recordData{6})) >> 4;
2097
+ switch ($vertAlign) {
2098
+ case 0:
2099
+ $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_TOP);
2100
+ break;
2101
+ case 1:
2102
+ $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
2103
+ break;
2104
+ case 2:
2105
+ $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_BOTTOM);
2106
+ break;
2107
+ case 3:
2108
+ $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_JUSTIFY);
2109
+ break;
2110
+ }
2111
+
2112
+ if ($this->_version == self::XLS_BIFF8) {
2113
+ // offset: 7; size: 1; XF_ROTATION: Text rotation angle
2114
+ $angle = ord($recordData{7});
2115
+ $rotation = 0;
2116
+ if ($angle <= 90) {
2117
+ $rotation = $angle;
2118
+ } else if ($angle <= 180) {
2119
+ $rotation = 90 - $angle;
2120
+ } else if ($angle == 255) {
2121
+ $rotation = -165;
2122
+ }
2123
+ $objStyle->getAlignment()->setTextRotation($rotation);
2124
+
2125
+ // offset: 8; size: 1; Indentation, shrink to cell size, and text direction
2126
+ // bit: 3-0; mask: 0x0F; indent level
2127
+ $indent = (0x0F & ord($recordData{8})) >> 0;
2128
+ $objStyle->getAlignment()->setIndent($indent);
2129
+
2130
+ // bit: 4; mask: 0x10; 1 = shrink content to fit into cell
2131
+ $shrinkToFit = (0x10 & ord($recordData{8})) >> 4;
2132
+ switch ($shrinkToFit) {
2133
+ case 0:
2134
+ $objStyle->getAlignment()->setShrinkToFit(false);
2135
+ break;
2136
+ case 1:
2137
+ $objStyle->getAlignment()->setShrinkToFit(true);
2138
+ break;
2139
+ }
2140
+
2141
+ // offset: 9; size: 1; Flags used for attribute groups
2142
+
2143
+ // offset: 10; size: 4; Cell border lines and background area
2144
+ // bit: 3-0; mask: 0x0000000F; left style
2145
+ if ($bordersLeftStyle = self::_mapBorderStyle((0x0000000F & self::_GetInt4d($recordData, 10)) >> 0)) {
2146
+ $objStyle->getBorders()->getLeft()->setBorderStyle($bordersLeftStyle);
2147
+ }
2148
+ // bit: 7-4; mask: 0x000000F0; right style
2149
+ if ($bordersRightStyle = self::_mapBorderStyle((0x000000F0 & self::_GetInt4d($recordData, 10)) >> 4)) {
2150
+ $objStyle->getBorders()->getRight()->setBorderStyle($bordersRightStyle);
2151
+ }
2152
+ // bit: 11-8; mask: 0x00000F00; top style
2153
+ if ($bordersTopStyle = self::_mapBorderStyle((0x00000F00 & self::_GetInt4d($recordData, 10)) >> 8)) {
2154
+ $objStyle->getBorders()->getTop()->setBorderStyle($bordersTopStyle);
2155
+ }
2156
+ // bit: 15-12; mask: 0x0000F000; bottom style
2157
+ if ($bordersBottomStyle = self::_mapBorderStyle((0x0000F000 & self::_GetInt4d($recordData, 10)) >> 12)) {
2158
+ $objStyle->getBorders()->getBottom()->setBorderStyle($bordersBottomStyle);
2159
+ }
2160
+ // bit: 22-16; mask: 0x007F0000; left color
2161
+ $objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & self::_GetInt4d($recordData, 10)) >> 16;
2162
+
2163
+ // bit: 29-23; mask: 0x3F800000; right color
2164
+ $objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & self::_GetInt4d($recordData, 10)) >> 23;
2165
+
2166
+ // bit: 30; mask: 0x40000000; 1 = diagonal line from top left to right bottom
2167
+ $diagonalDown = (0x40000000 & self::_GetInt4d($recordData, 10)) >> 30 ?
2168
+ true : false;
2169
+
2170
+ // bit: 31; mask: 0x80000000; 1 = diagonal line from bottom left to top right
2171
+ $diagonalUp = (0x80000000 & self::_GetInt4d($recordData, 10)) >> 31 ?
2172
+ true : false;
2173
+
2174
+ if ($diagonalUp == false && $diagonalDown == false) {
2175
+ $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_NONE);
2176
+ } elseif ($diagonalUp == true && $diagonalDown == false) {
2177
+ $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_UP);
2178
+ } elseif ($diagonalUp == false && $diagonalDown == true) {
2179
+ $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_DOWN);
2180
+ } elseif ($diagonalUp == true && $diagonalDown == true) {
2181
+ $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_BOTH);
2182
+ }
2183
+
2184
+ // offset: 14; size: 4;
2185
+ // bit: 6-0; mask: 0x0000007F; top color
2186
+ $objStyle->getBorders()->getTop()->colorIndex = (0x0000007F & self::_GetInt4d($recordData, 14)) >> 0;
2187
+
2188
+ // bit: 13-7; mask: 0x00003F80; bottom color
2189
+ $objStyle->getBorders()->getBottom()->colorIndex = (0x00003F80 & self::_GetInt4d($recordData, 14)) >> 7;
2190
+
2191
+ // bit: 20-14; mask: 0x001FC000; diagonal color
2192
+ $objStyle->getBorders()->getDiagonal()->colorIndex = (0x001FC000 & self::_GetInt4d($recordData, 14)) >> 14;
2193
+
2194
+ // bit: 24-21; mask: 0x01E00000; diagonal style
2195
+ if ($bordersDiagonalStyle = self::_mapBorderStyle((0x01E00000 & self::_GetInt4d($recordData, 14)) >> 21)) {
2196
+ $objStyle->getBorders()->getDiagonal()->setBorderStyle($bordersDiagonalStyle);
2197
+ }
2198
+
2199
+ // bit: 31-26; mask: 0xFC000000 fill pattern
2200
+ if ($fillType = self::_mapFillPattern((0xFC000000 & self::_GetInt4d($recordData, 14)) >> 26)) {
2201
+ $objStyle->getFill()->setFillType($fillType);
2202
+ }
2203
+ // offset: 18; size: 2; pattern and background colour
2204
+ // bit: 6-0; mask: 0x007F; color index for pattern color
2205
+ $objStyle->getFill()->startcolorIndex = (0x007F & self::_GetInt2d($recordData, 18)) >> 0;
2206
+
2207
+ // bit: 13-7; mask: 0x3F80; color index for pattern background
2208
+ $objStyle->getFill()->endcolorIndex = (0x3F80 & self::_GetInt2d($recordData, 18)) >> 7;
2209
+ } else {
2210
+ // BIFF5
2211
+
2212
+ // offset: 7; size: 1; Text orientation and flags
2213
+ $orientationAndFlags = ord($recordData{7});
2214
+
2215
+ // bit: 1-0; mask: 0x03; XF_ORIENTATION: Text orientation
2216
+ $xfOrientation = (0x03 & $orientationAndFlags) >> 0;
2217
+ switch ($xfOrientation) {
2218
+ case 0:
2219
+ $objStyle->getAlignment()->setTextRotation(0);
2220
+ break;
2221
+ case 1:
2222
+ $objStyle->getAlignment()->setTextRotation(-165);
2223
+ break;
2224
+ case 2:
2225
+ $objStyle->getAlignment()->setTextRotation(90);
2226
+ break;
2227
+ case 3:
2228
+ $objStyle->getAlignment()->setTextRotation(-90);
2229
+ break;
2230
+ }
2231
+
2232
+ // offset: 8; size: 4; cell border lines and background area
2233
+ $borderAndBackground = self::_GetInt4d($recordData, 8);
2234
+
2235
+ // bit: 6-0; mask: 0x0000007F; color index for pattern color
2236
+ $objStyle->getFill()->startcolorIndex = (0x0000007F & $borderAndBackground) >> 0;
2237
+
2238
+ // bit: 13-7; mask: 0x00003F80; color index for pattern background
2239
+ $objStyle->getFill()->endcolorIndex = (0x00003F80 & $borderAndBackground) >> 7;
2240
+
2241
+ // bit: 21-16; mask: 0x003F0000; fill pattern
2242
+ $objStyle->getFill()->setFillType(self::_mapFillPattern((0x003F0000 & $borderAndBackground) >> 16));
2243
+
2244
+ // bit: 24-22; mask: 0x01C00000; bottom line style
2245
+ $objStyle->getBorders()->getBottom()->setBorderStyle(self::_mapBorderStyle((0x01C00000 & $borderAndBackground) >> 22));
2246
+
2247
+ // bit: 31-25; mask: 0xFE000000; bottom line color
2248
+ $objStyle->getBorders()->getBottom()->colorIndex = (0xFE000000 & $borderAndBackground) >> 25;
2249
+
2250
+ // offset: 12; size: 4; cell border lines
2251
+ $borderLines = self::_GetInt4d($recordData, 12);
2252
+
2253
+ // bit: 2-0; mask: 0x00000007; top line style
2254
+ $objStyle->getBorders()->getTop()->setBorderStyle(self::_mapBorderStyle((0x00000007 & $borderLines) >> 0));
2255
+
2256
+ // bit: 5-3; mask: 0x00000038; left line style
2257
+ $objStyle->getBorders()->getLeft()->setBorderStyle(self::_mapBorderStyle((0x00000038 & $borderLines) >> 3));
2258
+
2259
+ // bit: 8-6; mask: 0x000001C0; right line style
2260
+ $objStyle->getBorders()->getRight()->setBorderStyle(self::_mapBorderStyle((0x000001C0 & $borderLines) >> 6));
2261
+
2262
+ // bit: 15-9; mask: 0x0000FE00; top line color index
2263
+ $objStyle->getBorders()->getTop()->colorIndex = (0x0000FE00 & $borderLines) >> 9;
2264
+
2265
+ // bit: 22-16; mask: 0x007F0000; left line color index
2266
+ $objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & $borderLines) >> 16;
2267
+
2268
+ // bit: 29-23; mask: 0x3F800000; right line color index
2269
+ $objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & $borderLines) >> 23;
2270
+ }
2271
+
2272
+ // add cellStyleXf or cellXf and update mapping
2273
+ if ($isCellStyleXf) {
2274
+ // we only read one style XF record which is always the first
2275
+ if ($this->_xfIndex == 0) {
2276
+ $this->_phpExcel->addCellStyleXf($objStyle);
2277
+ $this->_mapCellStyleXfIndex[$this->_xfIndex] = 0;
2278
+ }
2279
+ } else {
2280
+ // we read all cell XF records
2281
+ $this->_phpExcel->addCellXf($objStyle);
2282
+ $this->_mapCellXfIndex[$this->_xfIndex] = count($this->_phpExcel->getCellXfCollection()) - 1;
2283
+ }
2284
+
2285
+ // update XF index for when we read next record
2286
+ ++$this->_xfIndex;
2287
+ }
2288
+ }
2289
+
2290
+
2291
+ /**
2292
+ *
2293
+ */
2294
+ private function _readXfExt()
2295
+ {
2296
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2297
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2298
+
2299
+ // move stream pointer to next record
2300
+ $this->_pos += 4 + $length;
2301
+
2302
+ if (!$this->_readDataOnly) {
2303
+ // offset: 0; size: 2; 0x087D = repeated header
2304
+
2305
+ // offset: 2; size: 2
2306
+
2307
+ // offset: 4; size: 8; not used
2308
+
2309
+ // offset: 12; size: 2; record version
2310
+
2311
+ // offset: 14; size: 2; index to XF record which this record modifies
2312
+ $ixfe = self::_GetInt2d($recordData, 14);
2313
+
2314
+ // offset: 16; size: 2; not used
2315
+
2316
+ // offset: 18; size: 2; number of extension properties that follow
2317
+ $cexts = self::_GetInt2d($recordData, 18);
2318
+
2319
+ // start reading the actual extension data
2320
+ $offset = 20;
2321
+ while ($offset < $length) {
2322
+ // extension type
2323
+ $extType = self::_GetInt2d($recordData, $offset);
2324
+
2325
+ // extension length
2326
+ $cb = self::_GetInt2d($recordData, $offset + 2);
2327
+
2328
+ // extension data
2329
+ $extData = substr($recordData, $offset + 4, $cb);
2330
+
2331
+ switch ($extType) {
2332
+ case 4: // fill start color
2333
+ $xclfType = self::_GetInt2d($extData, 0); // color type
2334
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2335
+
2336
+ if ($xclfType == 2) {
2337
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2338
+
2339
+ // modify the relevant style property
2340
+ if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2341
+ $fill = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFill();
2342
+ $fill->getStartColor()->setRGB($rgb);
2343
+ unset($fill->startcolorIndex); // normal color index does not apply, discard
2344
+ }
2345
+ }
2346
+ break;
2347
+
2348
+ case 5: // fill end color
2349
+ $xclfType = self::_GetInt2d($extData, 0); // color type
2350
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2351
+
2352
+ if ($xclfType == 2) {
2353
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2354
+
2355
+ // modify the relevant style property
2356
+ if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2357
+ $fill = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFill();
2358
+ $fill->getEndColor()->setRGB($rgb);
2359
+ unset($fill->endcolorIndex); // normal color index does not apply, discard
2360
+ }
2361
+ }
2362
+ break;
2363
+
2364
+ case 7: // border color top
2365
+ $xclfType = self::_GetInt2d($extData, 0); // color type
2366
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2367
+
2368
+ if ($xclfType == 2) {
2369
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2370
+
2371
+ // modify the relevant style property
2372
+ if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2373
+ $top = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getTop();
2374
+ $top->getColor()->setRGB($rgb);
2375
+ unset($top->colorIndex); // normal color index does not apply, discard
2376
+ }
2377
+ }
2378
+ break;
2379
+
2380
+ case 8: // border color bottom
2381
+ $xclfType = self::_GetInt2d($extData, 0); // color type
2382
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2383
+
2384
+ if ($xclfType == 2) {
2385
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2386
+
2387
+ // modify the relevant style property
2388
+ if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2389
+ $bottom = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getBottom();
2390
+ $bottom->getColor()->setRGB($rgb);
2391
+ unset($bottom->colorIndex); // normal color index does not apply, discard
2392
+ }
2393
+ }
2394
+ break;
2395
+
2396
+ case 9: // border color left
2397
+ $xclfType = self::_GetInt2d($extData, 0); // color type
2398
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2399
+
2400
+ if ($xclfType == 2) {
2401
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2402
+
2403
+ // modify the relevant style property
2404
+ if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2405
+ $left = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getLeft();
2406
+ $left->getColor()->setRGB($rgb);
2407
+ unset($left->colorIndex); // normal color index does not apply, discard
2408
+ }
2409
+ }
2410
+ break;
2411
+
2412
+ case 10: // border color right
2413
+ $xclfType = self::_GetInt2d($extData, 0); // color type
2414
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2415
+
2416
+ if ($xclfType == 2) {
2417
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2418
+
2419
+ // modify the relevant style property
2420
+ if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2421
+ $right = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getRight();
2422
+ $right->getColor()->setRGB($rgb);
2423
+ unset($right->colorIndex); // normal color index does not apply, discard
2424
+ }
2425
+ }
2426
+ break;
2427
+
2428
+ case 11: // border color diagonal
2429
+ $xclfType = self::_GetInt2d($extData, 0); // color type
2430
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2431
+
2432
+ if ($xclfType == 2) {
2433
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2434
+
2435
+ // modify the relevant style property
2436
+ if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2437
+ $diagonal = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getDiagonal();
2438
+ $diagonal->getColor()->setRGB($rgb);
2439
+ unset($diagonal->colorIndex); // normal color index does not apply, discard
2440
+ }
2441
+ }
2442
+ break;
2443
+
2444
+ case 13: // font color
2445
+ $xclfType = self::_GetInt2d($extData, 0); // color type
2446
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2447
+
2448
+ if ($xclfType == 2) {
2449
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2450
+
2451
+ // modify the relevant style property
2452
+ if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2453
+ $font = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFont();
2454
+ $font->getColor()->setRGB($rgb);
2455
+ unset($font->colorIndex); // normal color index does not apply, discard
2456
+ }
2457
+ }
2458
+ break;
2459
+ }
2460
+
2461
+ $offset += $cb;
2462
+ }
2463
+ }
2464
+
2465
+ }
2466
+
2467
+
2468
+ /**
2469
+ * Read STYLE record
2470
+ */
2471
+ private function _readStyle()
2472
+ {
2473
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2474
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2475
+
2476
+ // move stream pointer to next record
2477
+ $this->_pos += 4 + $length;
2478
+
2479
+ if (!$this->_readDataOnly) {
2480
+ // offset: 0; size: 2; index to XF record and flag for built-in style
2481
+ $ixfe = self::_GetInt2d($recordData, 0);
2482
+
2483
+ // bit: 11-0; mask 0x0FFF; index to XF record
2484
+ $xfIndex = (0x0FFF & $ixfe) >> 0;
2485
+
2486
+ // bit: 15; mask 0x8000; 0 = user-defined style, 1 = built-in style
2487
+ $isBuiltIn = (bool) ((0x8000 & $ixfe) >> 15);
2488
+
2489
+ if ($isBuiltIn) {
2490
+ // offset: 2; size: 1; identifier for built-in style
2491
+ $builtInId = ord($recordData{2});
2492
+
2493
+ switch ($builtInId) {
2494
+ case 0x00:
2495
+ // currently, we are not using this for anything
2496
+ break;
2497
+
2498
+ default:
2499
+ break;
2500
+ }
2501
+
2502
+ } else {
2503
+ // user-defined; not supported by PHPExcel
2504
+ }
2505
+ }
2506
+ }
2507
+
2508
+
2509
+ /**
2510
+ * Read PALETTE record
2511
+ */
2512
+ private function _readPalette()
2513
+ {
2514
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2515
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2516
+
2517
+ // move stream pointer to next record
2518
+ $this->_pos += 4 + $length;
2519
+
2520
+ if (!$this->_readDataOnly) {
2521
+ // offset: 0; size: 2; number of following colors
2522
+ $nm = self::_GetInt2d($recordData, 0);
2523
+
2524
+ // list of RGB colors
2525
+ for ($i = 0; $i < $nm; ++$i) {
2526
+ $rgb = substr($recordData, 2 + 4 * $i, 4);
2527
+ $this->_palette[] = self::_readRGB($rgb);
2528
+ }
2529
+ }
2530
+ }
2531
+
2532
+
2533
+ /**
2534
+ * SHEET
2535
+ *
2536
+ * This record is located in the Workbook Globals
2537
+ * Substream and represents a sheet inside the workbook.
2538
+ * One SHEET record is written for each sheet. It stores the
2539
+ * sheet name and a stream offset to the BOF record of the
2540
+ * respective Sheet Substream within the Workbook Stream.
2541
+ *
2542
+ * -- "OpenOffice.org's Documentation of the Microsoft
2543
+ * Excel File Format"
2544
+ */
2545
+ private function _readSheet()
2546
+ {
2547
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2548
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2549
+
2550
+ // offset: 0; size: 4; absolute stream position of the BOF record of the sheet
2551
+ // NOTE: not encrypted
2552
+ $rec_offset = self::_GetInt4d($this->_data, $this->_pos + 4);
2553
+
2554
+ // move stream pointer to next record
2555
+ $this->_pos += 4 + $length;
2556
+
2557
+ // offset: 4; size: 1; sheet state
2558
+ switch (ord($recordData{4})) {
2559
+ case 0x00: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE; break;
2560
+ case 0x01: $sheetState = PHPExcel_Worksheet::SHEETSTATE_HIDDEN; break;
2561
+ case 0x02: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VERYHIDDEN; break;
2562
+ default: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE; break;
2563
+ }
2564
+
2565
+ // offset: 5; size: 1; sheet type
2566
+ $sheetType = ord($recordData{5});
2567
+
2568
+ // offset: 6; size: var; sheet name
2569
+ if ($this->_version == self::XLS_BIFF8) {
2570
+ $string = self::_readUnicodeStringShort(substr($recordData, 6));
2571
+ $rec_name = $string['value'];
2572
+ } elseif ($this->_version == self::XLS_BIFF7) {
2573
+ $string = $this->_readByteStringShort(substr($recordData, 6));
2574
+ $rec_name = $string['value'];
2575
+ }
2576
+
2577
+ $this->_sheets[] = array(
2578
+ 'name' => $rec_name,
2579
+ 'offset' => $rec_offset,
2580
+ 'sheetState' => $sheetState,
2581
+ 'sheetType' => $sheetType,
2582
+ );
2583
+ }
2584
+
2585
+
2586
+ /**
2587
+ * Read EXTERNALBOOK record
2588
+ */
2589
+ private function _readExternalBook()
2590
+ {
2591
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2592
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2593
+
2594
+ // move stream pointer to next record
2595
+ $this->_pos += 4 + $length;
2596
+
2597
+ // offset within record data
2598
+ $offset = 0;
2599
+
2600
+ // there are 4 types of records
2601
+ if (strlen($recordData) > 4) {
2602
+ // external reference
2603
+ // offset: 0; size: 2; number of sheet names ($nm)
2604
+ $nm = self::_GetInt2d($recordData, 0);
2605
+ $offset += 2;
2606
+
2607
+ // offset: 2; size: var; encoded URL without sheet name (Unicode string, 16-bit length)
2608
+ $encodedUrlString = self::_readUnicodeStringLong(substr($recordData, 2));
2609
+ $offset += $encodedUrlString['size'];
2610
+
2611
+ // offset: var; size: var; list of $nm sheet names (Unicode strings, 16-bit length)
2612
+ $externalSheetNames = array();
2613
+ for ($i = 0; $i < $nm; ++$i) {
2614
+ $externalSheetNameString = self::_readUnicodeStringLong(substr($recordData, $offset));
2615
+ $externalSheetNames[] = $externalSheetNameString['value'];
2616
+ $offset += $externalSheetNameString['size'];
2617
+ }
2618
+
2619
+ // store the record data
2620
+ $this->_externalBooks[] = array(
2621
+ 'type' => 'external',
2622
+ 'encodedUrl' => $encodedUrlString['value'],
2623
+ 'externalSheetNames' => $externalSheetNames,
2624
+ );
2625
+
2626
+ } elseif (substr($recordData, 2, 2) == pack('CC', 0x01, 0x04)) {
2627
+ // internal reference
2628
+ // offset: 0; size: 2; number of sheet in this document
2629
+ // offset: 2; size: 2; 0x01 0x04
2630
+ $this->_externalBooks[] = array(
2631
+ 'type' => 'internal',
2632
+ );
2633
+ } elseif (substr($recordData, 0, 4) == pack('vCC', 0x0001, 0x01, 0x3A)) {
2634
+ // add-in function
2635
+ // offset: 0; size: 2; 0x0001
2636
+ $this->_externalBooks[] = array(
2637
+ 'type' => 'addInFunction',
2638
+ );
2639
+ } elseif (substr($recordData, 0, 2) == pack('v', 0x0000)) {
2640
+ // DDE links, OLE links
2641
+ // offset: 0; size: 2; 0x0000
2642
+ // offset: 2; size: var; encoded source document name
2643
+ $this->_externalBooks[] = array(
2644
+ 'type' => 'DDEorOLE',
2645
+ );
2646
+ }
2647
+ }
2648
+
2649
+
2650
+ /**
2651
+ * Read EXTERNNAME record.
2652
+ */
2653
+ private function _readExternName()
2654
+ {
2655
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2656
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2657
+
2658
+ // move stream pointer to next record
2659
+ $this->_pos += 4 + $length;
2660
+
2661
+ // external sheet references provided for named cells
2662
+ if ($this->_version == self::XLS_BIFF8) {
2663
+ // offset: 0; size: 2; options
2664
+ $options = self::_GetInt2d($recordData, 0);
2665
+
2666
+ // offset: 2; size: 2;
2667
+
2668
+ // offset: 4; size: 2; not used
2669
+
2670
+ // offset: 6; size: var
2671
+ $nameString = self::_readUnicodeStringShort(substr($recordData, 6));
2672
+
2673
+ // offset: var; size: var; formula data
2674
+ $offset = 6 + $nameString['size'];
2675
+ $formula = $this->_getFormulaFromStructure(substr($recordData, $offset));
2676
+
2677
+ $this->_externalNames[] = array(
2678
+ 'name' => $nameString['value'],
2679
+ 'formula' => $formula,
2680
+ );
2681
+ }
2682
+ }
2683
+
2684
+
2685
+ /**
2686
+ * Read EXTERNSHEET record
2687
+ */
2688
+ private function _readExternSheet()
2689
+ {
2690
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2691
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2692
+
2693
+ // move stream pointer to next record
2694
+ $this->_pos += 4 + $length;
2695
+
2696
+ // external sheet references provided for named cells
2697
+ if ($this->_version == self::XLS_BIFF8) {
2698
+ // offset: 0; size: 2; number of following ref structures
2699
+ $nm = self::_GetInt2d($recordData, 0);
2700
+ for ($i = 0; $i < $nm; ++$i) {
2701
+ $this->_ref[] = array(
2702
+ // offset: 2 + 6 * $i; index to EXTERNALBOOK record
2703
+ 'externalBookIndex' => self::_GetInt2d($recordData, 2 + 6 * $i),
2704
+ // offset: 4 + 6 * $i; index to first sheet in EXTERNALBOOK record
2705
+ 'firstSheetIndex' => self::_GetInt2d($recordData, 4 + 6 * $i),
2706
+ // offset: 6 + 6 * $i; index to last sheet in EXTERNALBOOK record
2707
+ 'lastSheetIndex' => self::_GetInt2d($recordData, 6 + 6 * $i),
2708
+ );
2709
+ }
2710
+ }
2711
+ }
2712
+
2713
+
2714
+ /**
2715
+ * DEFINEDNAME
2716
+ *
2717
+ * This record is part of a Link Table. It contains the name
2718
+ * and the token array of an internal defined name. Token
2719
+ * arrays of defined names contain tokens with aberrant
2720
+ * token classes.
2721
+ *
2722
+ * -- "OpenOffice.org's Documentation of the Microsoft
2723
+ * Excel File Format"
2724
+ */
2725
+ private function _readDefinedName()
2726
+ {
2727
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2728
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2729
+
2730
+ // move stream pointer to next record
2731
+ $this->_pos += 4 + $length;
2732
+
2733
+ if ($this->_version == self::XLS_BIFF8) {
2734
+ // retrieves named cells
2735
+
2736
+ // offset: 0; size: 2; option flags
2737
+ $opts = self::_GetInt2d($recordData, 0);
2738
+
2739
+ // bit: 5; mask: 0x0020; 0 = user-defined name, 1 = built-in-name
2740
+ $isBuiltInName = (0x0020 & $opts) >> 5;
2741
+
2742
+ // offset: 2; size: 1; keyboard shortcut
2743
+
2744
+ // offset: 3; size: 1; length of the name (character count)
2745
+ $nlen = ord($recordData{3});
2746
+
2747
+ // offset: 4; size: 2; size of the formula data (it can happen that this is zero)
2748
+ // note: there can also be additional data, this is not included in $flen
2749
+ $flen = self::_GetInt2d($recordData, 4);
2750
+
2751
+ // offset: 8; size: 2; 0=Global name, otherwise index to sheet (1-based)
2752
+ $scope = self::_GetInt2d($recordData, 8);
2753
+
2754
+ // offset: 14; size: var; Name (Unicode string without length field)
2755
+ $string = self::_readUnicodeString(substr($recordData, 14), $nlen);
2756
+
2757
+ // offset: var; size: $flen; formula data
2758
+ $offset = 14 + $string['size'];
2759
+ $formulaStructure = pack('v', $flen) . substr($recordData, $offset);
2760
+
2761
+ try {
2762
+ $formula = $this->_getFormulaFromStructure($formulaStructure);
2763
+ } catch (PHPExcel_Exception $e) {
2764
+ $formula = '';
2765
+ }
2766
+
2767
+ $this->_definedname[] = array(
2768
+ 'isBuiltInName' => $isBuiltInName,
2769
+ 'name' => $string['value'],
2770
+ 'formula' => $formula,
2771
+ 'scope' => $scope,
2772
+ );
2773
+ }
2774
+ }
2775
+
2776
+
2777
+ /**
2778
+ * Read MSODRAWINGGROUP record
2779
+ */
2780
+ private function _readMsoDrawingGroup()
2781
+ {
2782
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2783
+
2784
+ // get spliced record data
2785
+ $splicedRecordData = $this->_getSplicedRecordData();
2786
+ $recordData = $splicedRecordData['recordData'];
2787
+
2788
+ $this->_drawingGroupData .= $recordData;
2789
+ }
2790
+
2791
+
2792
+ /**
2793
+ * SST - Shared String Table
2794
+ *
2795
+ * This record contains a list of all strings used anywhere
2796
+ * in the workbook. Each string occurs only once. The
2797
+ * workbook uses indexes into the list to reference the
2798
+ * strings.
2799
+ *
2800
+ * -- "OpenOffice.org's Documentation of the Microsoft
2801
+ * Excel File Format"
2802
+ **/
2803
+ private function _readSst()
2804
+ {
2805
+ // offset within (spliced) record data
2806
+ $pos = 0;
2807
+
2808
+ // get spliced record data
2809
+ $splicedRecordData = $this->_getSplicedRecordData();
2810
+
2811
+ $recordData = $splicedRecordData['recordData'];
2812
+ $spliceOffsets = $splicedRecordData['spliceOffsets'];
2813
+
2814
+ // offset: 0; size: 4; total number of strings in the workbook
2815
+ $pos += 4;
2816
+
2817
+ // offset: 4; size: 4; number of following strings ($nm)
2818
+ $nm = self::_GetInt4d($recordData, 4);
2819
+ $pos += 4;
2820
+
2821
+ // loop through the Unicode strings (16-bit length)
2822
+ for ($i = 0; $i < $nm; ++$i) {
2823
+
2824
+ // number of characters in the Unicode string
2825
+ $numChars = self::_GetInt2d($recordData, $pos);
2826
+ $pos += 2;
2827
+
2828
+ // option flags
2829
+ $optionFlags = ord($recordData{$pos});
2830
+ ++$pos;
2831
+
2832
+ // bit: 0; mask: 0x01; 0 = compressed; 1 = uncompressed
2833
+ $isCompressed = (($optionFlags & 0x01) == 0) ;
2834
+
2835
+ // bit: 2; mask: 0x02; 0 = ordinary; 1 = Asian phonetic
2836
+ $hasAsian = (($optionFlags & 0x04) != 0);
2837
+
2838
+ // bit: 3; mask: 0x03; 0 = ordinary; 1 = Rich-Text
2839
+ $hasRichText = (($optionFlags & 0x08) != 0);
2840
+
2841
+ if ($hasRichText) {
2842
+ // number of Rich-Text formatting runs
2843
+ $formattingRuns = self::_GetInt2d($recordData, $pos);
2844
+ $pos += 2;
2845
+ }
2846
+
2847
+ if ($hasAsian) {
2848
+ // size of Asian phonetic setting
2849
+ $extendedRunLength = self::_GetInt4d($recordData, $pos);
2850
+ $pos += 4;
2851
+ }
2852
+
2853
+ // expected byte length of character array if not split
2854
+ $len = ($isCompressed) ? $numChars : $numChars * 2;
2855
+
2856
+ // look up limit position
2857
+ foreach ($spliceOffsets as $spliceOffset) {
2858
+ // it can happen that the string is empty, therefore we need
2859
+ // <= and not just <
2860
+ if ($pos <= $spliceOffset) {
2861
+ $limitpos = $spliceOffset;
2862
+ break;
2863
+ }
2864
+ }
2865
+
2866
+ if ($pos + $len <= $limitpos) {
2867
+ // character array is not split between records
2868
+
2869
+ $retstr = substr($recordData, $pos, $len);
2870
+ $pos += $len;
2871
+
2872
+ } else {
2873
+ // character array is split between records
2874
+
2875
+ // first part of character array
2876
+ $retstr = substr($recordData, $pos, $limitpos - $pos);
2877
+
2878
+ $bytesRead = $limitpos - $pos;
2879
+
2880
+ // remaining characters in Unicode string
2881
+ $charsLeft = $numChars - (($isCompressed) ? $bytesRead : ($bytesRead / 2));
2882
+
2883
+ $pos = $limitpos;
2884
+
2885
+ // keep reading the characters
2886
+ while ($charsLeft > 0) {
2887
+
2888
+ // look up next limit position, in case the string span more than one continue record
2889
+ foreach ($spliceOffsets as $spliceOffset) {
2890
+ if ($pos < $spliceOffset) {
2891
+ $limitpos = $spliceOffset;
2892
+ break;
2893
+ }
2894
+ }
2895
+
2896
+ // repeated option flags
2897
+ // OpenOffice.org documentation 5.21
2898
+ $option = ord($recordData{$pos});
2899
+ ++$pos;
2900
+
2901
+ if ($isCompressed && ($option == 0)) {
2902
+ // 1st fragment compressed
2903
+ // this fragment compressed
2904
+ $len = min($charsLeft, $limitpos - $pos);
2905
+ $retstr .= substr($recordData, $pos, $len);
2906
+ $charsLeft -= $len;
2907
+ $isCompressed = true;
2908
+
2909
+ } elseif (!$isCompressed && ($option != 0)) {
2910
+ // 1st fragment uncompressed
2911
+ // this fragment uncompressed
2912
+ $len = min($charsLeft * 2, $limitpos - $pos);
2913
+ $retstr .= substr($recordData, $pos, $len);
2914
+ $charsLeft -= $len / 2;
2915
+ $isCompressed = false;
2916
+
2917
+ } elseif (!$isCompressed && ($option == 0)) {
2918
+ // 1st fragment uncompressed
2919
+ // this fragment compressed
2920
+ $len = min($charsLeft, $limitpos - $pos);
2921
+ for ($j = 0; $j < $len; ++$j) {
2922
+ $retstr .= $recordData{$pos + $j} . chr(0);
2923
+ }
2924
+ $charsLeft -= $len;
2925
+ $isCompressed = false;
2926
+
2927
+ } else {
2928
+ // 1st fragment compressed
2929
+ // this fragment uncompressed
2930
+ $newstr = '';
2931
+ for ($j = 0; $j < strlen($retstr); ++$j) {
2932
+ $newstr .= $retstr[$j] . chr(0);
2933
+ }
2934
+ $retstr = $newstr;
2935
+ $len = min($charsLeft * 2, $limitpos - $pos);
2936
+ $retstr .= substr($recordData, $pos, $len);
2937
+ $charsLeft -= $len / 2;
2938
+ $isCompressed = false;
2939
+ }
2940
+
2941
+ $pos += $len;
2942
+ }
2943
+ }
2944
+
2945
+ // convert to UTF-8
2946
+ $retstr = self::_encodeUTF16($retstr, $isCompressed);
2947
+
2948
+ // read additional Rich-Text information, if any
2949
+ $fmtRuns = array();
2950
+ if ($hasRichText) {
2951
+ // list of formatting runs
2952
+ for ($j = 0; $j < $formattingRuns; ++$j) {
2953
+ // first formatted character; zero-based
2954
+ $charPos = self::_GetInt2d($recordData, $pos + $j * 4);
2955
+
2956
+ // index to font record
2957
+ $fontIndex = self::_GetInt2d($recordData, $pos + 2 + $j * 4);
2958
+
2959
+ $fmtRuns[] = array(
2960
+ 'charPos' => $charPos,
2961
+ 'fontIndex' => $fontIndex,
2962
+ );
2963
+ }
2964
+ $pos += 4 * $formattingRuns;
2965
+ }
2966
+
2967
+ // read additional Asian phonetics information, if any
2968
+ if ($hasAsian) {
2969
+ // For Asian phonetic settings, we skip the extended string data
2970
+ $pos += $extendedRunLength;
2971
+ }
2972
+
2973
+ // store the shared sting
2974
+ $this->_sst[] = array(
2975
+ 'value' => $retstr,
2976
+ 'fmtRuns' => $fmtRuns,
2977
+ );
2978
+ }
2979
+
2980
+ // _getSplicedRecordData() takes care of moving current position in data stream
2981
+ }
2982
+
2983
+
2984
+ /**
2985
+ * Read PRINTGRIDLINES record
2986
+ */
2987
+ private function _readPrintGridlines()
2988
+ {
2989
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
2990
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
2991
+
2992
+ // move stream pointer to next record
2993
+ $this->_pos += 4 + $length;
2994
+
2995
+ if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
2996
+ // offset: 0; size: 2; 0 = do not print sheet grid lines; 1 = print sheet gridlines
2997
+ $printGridlines = (bool) self::_GetInt2d($recordData, 0);
2998
+ $this->_phpSheet->setPrintGridlines($printGridlines);
2999
+ }
3000
+ }
3001
+
3002
+
3003
+ /**
3004
+ * Read DEFAULTROWHEIGHT record
3005
+ */
3006
+ private function _readDefaultRowHeight()
3007
+ {
3008
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3009
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3010
+
3011
+ // move stream pointer to next record
3012
+ $this->_pos += 4 + $length;
3013
+
3014
+ // offset: 0; size: 2; option flags
3015
+ // offset: 2; size: 2; default height for unused rows, (twips 1/20 point)
3016
+ $height = self::_GetInt2d($recordData, 2);
3017
+ $this->_phpSheet->getDefaultRowDimension()->setRowHeight($height / 20);
3018
+ }
3019
+
3020
+
3021
+ /**
3022
+ * Read SHEETPR record
3023
+ */
3024
+ private function _readSheetPr()
3025
+ {
3026
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3027
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3028
+
3029
+ // move stream pointer to next record
3030
+ $this->_pos += 4 + $length;
3031
+
3032
+ // offset: 0; size: 2
3033
+
3034
+ // bit: 6; mask: 0x0040; 0 = outline buttons above outline group
3035
+ $isSummaryBelow = (0x0040 & self::_GetInt2d($recordData, 0)) >> 6;
3036
+ $this->_phpSheet->setShowSummaryBelow($isSummaryBelow);
3037
+
3038
+ // bit: 7; mask: 0x0080; 0 = outline buttons left of outline group
3039
+ $isSummaryRight = (0x0080 & self::_GetInt2d($recordData, 0)) >> 7;
3040
+ $this->_phpSheet->setShowSummaryRight($isSummaryRight);
3041
+
3042
+ // bit: 8; mask: 0x100; 0 = scale printout in percent, 1 = fit printout to number of pages
3043
+ // this corresponds to radio button setting in page setup dialog in Excel
3044
+ $this->_isFitToPages = (bool) ((0x0100 & self::_GetInt2d($recordData, 0)) >> 8);
3045
+ }
3046
+
3047
+
3048
+ /**
3049
+ * Read HORIZONTALPAGEBREAKS record
3050
+ */
3051
+ private function _readHorizontalPageBreaks()
3052
+ {
3053
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3054
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3055
+
3056
+ // move stream pointer to next record
3057
+ $this->_pos += 4 + $length;
3058
+
3059
+ if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
3060
+
3061
+ // offset: 0; size: 2; number of the following row index structures
3062
+ $nm = self::_GetInt2d($recordData, 0);
3063
+
3064
+ // offset: 2; size: 6 * $nm; list of $nm row index structures
3065
+ for ($i = 0; $i < $nm; ++$i) {
3066
+ $r = self::_GetInt2d($recordData, 2 + 6 * $i);
3067
+ $cf = self::_GetInt2d($recordData, 2 + 6 * $i + 2);
3068
+ $cl = self::_GetInt2d($recordData, 2 + 6 * $i + 4);
3069
+
3070
+ // not sure why two column indexes are necessary?
3071
+ $this->_phpSheet->setBreakByColumnAndRow($cf, $r, PHPExcel_Worksheet::BREAK_ROW);
3072
+ }
3073
+ }
3074
+ }
3075
+
3076
+
3077
+ /**
3078
+ * Read VERTICALPAGEBREAKS record
3079
+ */
3080
+ private function _readVerticalPageBreaks()
3081
+ {
3082
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3083
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3084
+
3085
+ // move stream pointer to next record
3086
+ $this->_pos += 4 + $length;
3087
+
3088
+ if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
3089
+ // offset: 0; size: 2; number of the following column index structures
3090
+ $nm = self::_GetInt2d($recordData, 0);
3091
+
3092
+ // offset: 2; size: 6 * $nm; list of $nm row index structures
3093
+ for ($i = 0; $i < $nm; ++$i) {
3094
+ $c = self::_GetInt2d($recordData, 2 + 6 * $i);
3095
+ $rf = self::_GetInt2d($recordData, 2 + 6 * $i + 2);
3096
+ $rl = self::_GetInt2d($recordData, 2 + 6 * $i + 4);
3097
+
3098
+ // not sure why two row indexes are necessary?
3099
+ $this->_phpSheet->setBreakByColumnAndRow($c, $rf, PHPExcel_Worksheet::BREAK_COLUMN);
3100
+ }
3101
+ }
3102
+ }
3103
+
3104
+
3105
+ /**
3106
+ * Read HEADER record
3107
+ */
3108
+ private function _readHeader()
3109
+ {
3110
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3111
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3112
+
3113
+ // move stream pointer to next record
3114
+ $this->_pos += 4 + $length;
3115
+
3116
+ if (!$this->_readDataOnly) {
3117
+ // offset: 0; size: var
3118
+ // realized that $recordData can be empty even when record exists
3119
+ if ($recordData) {
3120
+ if ($this->_version == self::XLS_BIFF8) {
3121
+ $string = self::_readUnicodeStringLong($recordData);
3122
+ } else {
3123
+ $string = $this->_readByteStringShort($recordData);
3124
+ }
3125
+
3126
+ $this->_phpSheet->getHeaderFooter()->setOddHeader($string['value']);
3127
+ $this->_phpSheet->getHeaderFooter()->setEvenHeader($string['value']);
3128
+ }
3129
+ }
3130
+ }
3131
+
3132
+
3133
+ /**
3134
+ * Read FOOTER record
3135
+ */
3136
+ private function _readFooter()
3137
+ {
3138
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3139
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3140
+
3141
+ // move stream pointer to next record
3142
+ $this->_pos += 4 + $length;
3143
+
3144
+ if (!$this->_readDataOnly) {
3145
+ // offset: 0; size: var
3146
+ // realized that $recordData can be empty even when record exists
3147
+ if ($recordData) {
3148
+ if ($this->_version == self::XLS_BIFF8) {
3149
+ $string = self::_readUnicodeStringLong($recordData);
3150
+ } else {
3151
+ $string = $this->_readByteStringShort($recordData);
3152
+ }
3153
+ $this->_phpSheet->getHeaderFooter()->setOddFooter($string['value']);
3154
+ $this->_phpSheet->getHeaderFooter()->setEvenFooter($string['value']);
3155
+ }
3156
+ }
3157
+ }
3158
+
3159
+
3160
+ /**
3161
+ * Read HCENTER record
3162
+ */
3163
+ private function _readHcenter()
3164
+ {
3165
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3166
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3167
+
3168
+ // move stream pointer to next record
3169
+ $this->_pos += 4 + $length;
3170
+
3171
+ if (!$this->_readDataOnly) {
3172
+ // offset: 0; size: 2; 0 = print sheet left aligned, 1 = print sheet centered horizontally
3173
+ $isHorizontalCentered = (bool) self::_GetInt2d($recordData, 0);
3174
+
3175
+ $this->_phpSheet->getPageSetup()->setHorizontalCentered($isHorizontalCentered);
3176
+ }
3177
+ }
3178
+
3179
+
3180
+ /**
3181
+ * Read VCENTER record
3182
+ */
3183
+ private function _readVcenter()
3184
+ {
3185
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3186
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3187
+
3188
+ // move stream pointer to next record
3189
+ $this->_pos += 4 + $length;
3190
+
3191
+ if (!$this->_readDataOnly) {
3192
+ // offset: 0; size: 2; 0 = print sheet aligned at top page border, 1 = print sheet vertically centered
3193
+ $isVerticalCentered = (bool) self::_GetInt2d($recordData, 0);
3194
+
3195
+ $this->_phpSheet->getPageSetup()->setVerticalCentered($isVerticalCentered);
3196
+ }
3197
+ }
3198
+
3199
+
3200
+ /**
3201
+ * Read LEFTMARGIN record
3202
+ */
3203
+ private function _readLeftMargin()
3204
+ {
3205
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3206
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3207
+
3208
+ // move stream pointer to next record
3209
+ $this->_pos += 4 + $length;
3210
+
3211
+ if (!$this->_readDataOnly) {
3212
+ // offset: 0; size: 8
3213
+ $this->_phpSheet->getPageMargins()->setLeft(self::_extractNumber($recordData));
3214
+ }
3215
+ }
3216
+
3217
+
3218
+ /**
3219
+ * Read RIGHTMARGIN record
3220
+ */
3221
+ private function _readRightMargin()
3222
+ {
3223
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3224
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3225
+
3226
+ // move stream pointer to next record
3227
+ $this->_pos += 4 + $length;
3228
+
3229
+ if (!$this->_readDataOnly) {
3230
+ // offset: 0; size: 8
3231
+ $this->_phpSheet->getPageMargins()->setRight(self::_extractNumber($recordData));
3232
+ }
3233
+ }
3234
+
3235
+
3236
+ /**
3237
+ * Read TOPMARGIN record
3238
+ */
3239
+ private function _readTopMargin()
3240
+ {
3241
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3242
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3243
+
3244
+ // move stream pointer to next record
3245
+ $this->_pos += 4 + $length;
3246
+
3247
+ if (!$this->_readDataOnly) {
3248
+ // offset: 0; size: 8
3249
+ $this->_phpSheet->getPageMargins()->setTop(self::_extractNumber($recordData));
3250
+ }
3251
+ }
3252
+
3253
+
3254
+ /**
3255
+ * Read BOTTOMMARGIN record
3256
+ */
3257
+ private function _readBottomMargin()
3258
+ {
3259
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3260
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3261
+
3262
+ // move stream pointer to next record
3263
+ $this->_pos += 4 + $length;
3264
+
3265
+ if (!$this->_readDataOnly) {
3266
+ // offset: 0; size: 8
3267
+ $this->_phpSheet->getPageMargins()->setBottom(self::_extractNumber($recordData));
3268
+ }
3269
+ }
3270
+
3271
+
3272
+ /**
3273
+ * Read PAGESETUP record
3274
+ */
3275
+ private function _readPageSetup()
3276
+ {
3277
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3278
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3279
+
3280
+ // move stream pointer to next record
3281
+ $this->_pos += 4 + $length;
3282
+
3283
+ if (!$this->_readDataOnly) {
3284
+ // offset: 0; size: 2; paper size
3285
+ $paperSize = self::_GetInt2d($recordData, 0);
3286
+
3287
+ // offset: 2; size: 2; scaling factor
3288
+ $scale = self::_GetInt2d($recordData, 2);
3289
+
3290
+ // offset: 6; size: 2; fit worksheet width to this number of pages, 0 = use as many as needed
3291
+ $fitToWidth = self::_GetInt2d($recordData, 6);
3292
+
3293
+ // offset: 8; size: 2; fit worksheet height to this number of pages, 0 = use as many as needed
3294
+ $fitToHeight = self::_GetInt2d($recordData, 8);
3295
+
3296
+ // offset: 10; size: 2; option flags
3297
+
3298
+ // bit: 1; mask: 0x0002; 0=landscape, 1=portrait
3299
+ $isPortrait = (0x0002 & self::_GetInt2d($recordData, 10)) >> 1;
3300
+
3301
+ // bit: 2; mask: 0x0004; 1= paper size, scaling factor, paper orient. not init
3302
+ // when this bit is set, do not use flags for those properties
3303
+ $isNotInit = (0x0004 & self::_GetInt2d($recordData, 10)) >> 2;
3304
+
3305
+ if (!$isNotInit) {
3306
+ $this->_phpSheet->getPageSetup()->setPaperSize($paperSize);
3307
+ switch ($isPortrait) {
3308
+ case 0: $this->_phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE); break;
3309
+ case 1: $this->_phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_PORTRAIT); break;
3310
+ }
3311
+
3312
+ $this->_phpSheet->getPageSetup()->setScale($scale, false);
3313
+ $this->_phpSheet->getPageSetup()->setFitToPage((bool) $this->_isFitToPages);
3314
+ $this->_phpSheet->getPageSetup()->setFitToWidth($fitToWidth, false);
3315
+ $this->_phpSheet->getPageSetup()->setFitToHeight($fitToHeight, false);
3316
+ }
3317
+
3318
+ // offset: 16; size: 8; header margin (IEEE 754 floating-point value)
3319
+ $marginHeader = self::_extractNumber(substr($recordData, 16, 8));
3320
+ $this->_phpSheet->getPageMargins()->setHeader($marginHeader);
3321
+
3322
+ // offset: 24; size: 8; footer margin (IEEE 754 floating-point value)
3323
+ $marginFooter = self::_extractNumber(substr($recordData, 24, 8));
3324
+ $this->_phpSheet->getPageMargins()->setFooter($marginFooter);
3325
+ }
3326
+ }
3327
+
3328
+
3329
+ /**
3330
+ * PROTECT - Sheet protection (BIFF2 through BIFF8)
3331
+ * if this record is omitted, then it also means no sheet protection
3332
+ */
3333
+ private function _readProtect()
3334
+ {
3335
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3336
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3337
+
3338
+ // move stream pointer to next record
3339
+ $this->_pos += 4 + $length;
3340
+
3341
+ if ($this->_readDataOnly) {
3342
+ return;
3343
+ }
3344
+
3345
+ // offset: 0; size: 2;
3346
+
3347
+ // bit 0, mask 0x01; 1 = sheet is protected
3348
+ $bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
3349
+ $this->_phpSheet->getProtection()->setSheet((bool)$bool);
3350
+ }
3351
+
3352
+
3353
+ /**
3354
+ * SCENPROTECT
3355
+ */
3356
+ private function _readScenProtect()
3357
+ {
3358
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3359
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3360
+
3361
+ // move stream pointer to next record
3362
+ $this->_pos += 4 + $length;
3363
+
3364
+ if ($this->_readDataOnly) {
3365
+ return;
3366
+ }
3367
+
3368
+ // offset: 0; size: 2;
3369
+
3370
+ // bit: 0, mask 0x01; 1 = scenarios are protected
3371
+ $bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
3372
+
3373
+ $this->_phpSheet->getProtection()->setScenarios((bool)$bool);
3374
+ }
3375
+
3376
+
3377
+ /**
3378
+ * OBJECTPROTECT
3379
+ */
3380
+ private function _readObjectProtect()
3381
+ {
3382
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3383
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3384
+
3385
+ // move stream pointer to next record
3386
+ $this->_pos += 4 + $length;
3387
+
3388
+ if ($this->_readDataOnly) {
3389
+ return;
3390
+ }
3391
+
3392
+ // offset: 0; size: 2;
3393
+
3394
+ // bit: 0, mask 0x01; 1 = objects are protected
3395
+ $bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
3396
+
3397
+ $this->_phpSheet->getProtection()->setObjects((bool)$bool);
3398
+ }
3399
+
3400
+
3401
+ /**
3402
+ * PASSWORD - Sheet protection (hashed) password (BIFF2 through BIFF8)
3403
+ */
3404
+ private function _readPassword()
3405
+ {
3406
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3407
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3408
+
3409
+ // move stream pointer to next record
3410
+ $this->_pos += 4 + $length;
3411
+
3412
+ if (!$this->_readDataOnly) {
3413
+ // offset: 0; size: 2; 16-bit hash value of password
3414
+ $password = strtoupper(dechex(self::_GetInt2d($recordData, 0))); // the hashed password
3415
+ $this->_phpSheet->getProtection()->setPassword($password, true);
3416
+ }
3417
+ }
3418
+
3419
+
3420
+ /**
3421
+ * Read DEFCOLWIDTH record
3422
+ */
3423
+ private function _readDefColWidth()
3424
+ {
3425
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3426
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3427
+
3428
+ // move stream pointer to next record
3429
+ $this->_pos += 4 + $length;
3430
+
3431
+ // offset: 0; size: 2; default column width
3432
+ $width = self::_GetInt2d($recordData, 0);
3433
+ if ($width != 8) {
3434
+ $this->_phpSheet->getDefaultColumnDimension()->setWidth($width);
3435
+ }
3436
+ }
3437
+
3438
+
3439
+ /**
3440
+ * Read COLINFO record
3441
+ */
3442
+ private function _readColInfo()
3443
+ {
3444
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3445
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3446
+
3447
+ // move stream pointer to next record
3448
+ $this->_pos += 4 + $length;
3449
+
3450
+ if (!$this->_readDataOnly) {
3451
+ // offset: 0; size: 2; index to first column in range
3452
+ $fc = self::_GetInt2d($recordData, 0); // first column index
3453
+
3454
+ // offset: 2; size: 2; index to last column in range
3455
+ $lc = self::_GetInt2d($recordData, 2); // first column index
3456
+
3457
+ // offset: 4; size: 2; width of the column in 1/256 of the width of the zero character
3458
+ $width = self::_GetInt2d($recordData, 4);
3459
+
3460
+ // offset: 6; size: 2; index to XF record for default column formatting
3461
+ $xfIndex = self::_GetInt2d($recordData, 6);
3462
+
3463
+ // offset: 8; size: 2; option flags
3464
+
3465
+ // bit: 0; mask: 0x0001; 1= columns are hidden
3466
+ $isHidden = (0x0001 & self::_GetInt2d($recordData, 8)) >> 0;
3467
+
3468
+ // bit: 10-8; mask: 0x0700; outline level of the columns (0 = no outline)
3469
+ $level = (0x0700 & self::_GetInt2d($recordData, 8)) >> 8;
3470
+
3471
+ // bit: 12; mask: 0x1000; 1 = collapsed
3472
+ $isCollapsed = (0x1000 & self::_GetInt2d($recordData, 8)) >> 12;
3473
+
3474
+ // offset: 10; size: 2; not used
3475
+
3476
+ for ($i = $fc; $i <= $lc; ++$i) {
3477
+ if ($lc == 255 || $lc == 256) {
3478
+ $this->_phpSheet->getDefaultColumnDimension()->setWidth($width / 256);
3479
+ break;
3480
+ }
3481
+ $this->_phpSheet->getColumnDimensionByColumn($i)->setWidth($width / 256);
3482
+ $this->_phpSheet->getColumnDimensionByColumn($i)->setVisible(!$isHidden);
3483
+ $this->_phpSheet->getColumnDimensionByColumn($i)->setOutlineLevel($level);
3484
+ $this->_phpSheet->getColumnDimensionByColumn($i)->setCollapsed($isCollapsed);
3485
+ $this->_phpSheet->getColumnDimensionByColumn($i)->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3486
+ }
3487
+ }
3488
+ }
3489
+
3490
+
3491
+ /**
3492
+ * ROW
3493
+ *
3494
+ * This record contains the properties of a single row in a
3495
+ * sheet. Rows and cells in a sheet are divided into blocks
3496
+ * of 32 rows.
3497
+ *
3498
+ * -- "OpenOffice.org's Documentation of the Microsoft
3499
+ * Excel File Format"
3500
+ */
3501
+ private function _readRow()
3502
+ {
3503
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3504
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3505
+
3506
+ // move stream pointer to next record
3507
+ $this->_pos += 4 + $length;
3508
+
3509
+ if (!$this->_readDataOnly) {
3510
+ // offset: 0; size: 2; index of this row
3511
+ $r = self::_GetInt2d($recordData, 0);
3512
+
3513
+ // offset: 2; size: 2; index to column of the first cell which is described by a cell record
3514
+
3515
+ // offset: 4; size: 2; index to column of the last cell which is described by a cell record, increased by 1
3516
+
3517
+ // offset: 6; size: 2;
3518
+
3519
+ // bit: 14-0; mask: 0x7FFF; height of the row, in twips = 1/20 of a point
3520
+ $height = (0x7FFF & self::_GetInt2d($recordData, 6)) >> 0;
3521
+
3522
+ // bit: 15: mask: 0x8000; 0 = row has custom height; 1= row has default height
3523
+ $useDefaultHeight = (0x8000 & self::_GetInt2d($recordData, 6)) >> 15;
3524
+
3525
+ if (!$useDefaultHeight) {
3526
+ $this->_phpSheet->getRowDimension($r + 1)->setRowHeight($height / 20);
3527
+ }
3528
+
3529
+ // offset: 8; size: 2; not used
3530
+
3531
+ // offset: 10; size: 2; not used in BIFF5-BIFF8
3532
+
3533
+ // offset: 12; size: 4; option flags and default row formatting
3534
+
3535
+ // bit: 2-0: mask: 0x00000007; outline level of the row
3536
+ $level = (0x00000007 & self::_GetInt4d($recordData, 12)) >> 0;
3537
+ $this->_phpSheet->getRowDimension($r + 1)->setOutlineLevel($level);
3538
+
3539
+ // bit: 4; mask: 0x00000010; 1 = outline group start or ends here... and is collapsed
3540
+ $isCollapsed = (0x00000010 & self::_GetInt4d($recordData, 12)) >> 4;
3541
+ $this->_phpSheet->getRowDimension($r + 1)->setCollapsed($isCollapsed);
3542
+
3543
+ // bit: 5; mask: 0x00000020; 1 = row is hidden
3544
+ $isHidden = (0x00000020 & self::_GetInt4d($recordData, 12)) >> 5;
3545
+ $this->_phpSheet->getRowDimension($r + 1)->setVisible(!$isHidden);
3546
+
3547
+ // bit: 7; mask: 0x00000080; 1 = row has explicit format
3548
+ $hasExplicitFormat = (0x00000080 & self::_GetInt4d($recordData, 12)) >> 7;
3549
+
3550
+ // bit: 27-16; mask: 0x0FFF0000; only applies when hasExplicitFormat = 1; index to XF record
3551
+ $xfIndex = (0x0FFF0000 & self::_GetInt4d($recordData, 12)) >> 16;
3552
+
3553
+ if ($hasExplicitFormat) {
3554
+ $this->_phpSheet->getRowDimension($r + 1)->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3555
+ }
3556
+ }
3557
+ }
3558
+
3559
+
3560
+ /**
3561
+ * Read RK record
3562
+ * This record represents a cell that contains an RK value
3563
+ * (encoded integer or floating-point value). If a
3564
+ * floating-point value cannot be encoded to an RK value,
3565
+ * a NUMBER record will be written. This record replaces the
3566
+ * record INTEGER written in BIFF2.
3567
+ *
3568
+ * -- "OpenOffice.org's Documentation of the Microsoft
3569
+ * Excel File Format"
3570
+ */
3571
+ private function _readRk()
3572
+ {
3573
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3574
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3575
+
3576
+ // move stream pointer to next record
3577
+ $this->_pos += 4 + $length;
3578
+
3579
+ // offset: 0; size: 2; index to row
3580
+ $row = self::_GetInt2d($recordData, 0);
3581
+
3582
+ // offset: 2; size: 2; index to column
3583
+ $column = self::_GetInt2d($recordData, 2);
3584
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3585
+
3586
+ // Read cell?
3587
+ if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3588
+ // offset: 4; size: 2; index to XF record
3589
+ $xfIndex = self::_GetInt2d($recordData, 4);
3590
+
3591
+ // offset: 6; size: 4; RK value
3592
+ $rknum = self::_GetInt4d($recordData, 6);
3593
+ $numValue = self::_GetIEEE754($rknum);
3594
+
3595
+ $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3596
+ if (!$this->_readDataOnly) {
3597
+ // add style information
3598
+ $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3599
+ }
3600
+
3601
+ // add cell
3602
+ $cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
3603
+ }
3604
+ }
3605
+
3606
+
3607
+ /**
3608
+ * Read LABELSST record
3609
+ * This record represents a cell that contains a string. It
3610
+ * replaces the LABEL record and RSTRING record used in
3611
+ * BIFF2-BIFF5.
3612
+ *
3613
+ * -- "OpenOffice.org's Documentation of the Microsoft
3614
+ * Excel File Format"
3615
+ */
3616
+ private function _readLabelSst()
3617
+ {
3618
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3619
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3620
+
3621
+ // move stream pointer to next record
3622
+ $this->_pos += 4 + $length;
3623
+
3624
+ // offset: 0; size: 2; index to row
3625
+ $row = self::_GetInt2d($recordData, 0);
3626
+
3627
+ // offset: 2; size: 2; index to column
3628
+ $column = self::_GetInt2d($recordData, 2);
3629
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3630
+
3631
+ // Read cell?
3632
+ if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3633
+ // offset: 4; size: 2; index to XF record
3634
+ $xfIndex = self::_GetInt2d($recordData, 4);
3635
+
3636
+ // offset: 6; size: 4; index to SST record
3637
+ $index = self::_GetInt4d($recordData, 6);
3638
+
3639
+ // add cell
3640
+ if (($fmtRuns = $this->_sst[$index]['fmtRuns']) && !$this->_readDataOnly) {
3641
+ // then we should treat as rich text
3642
+ $richText = new PHPExcel_RichText();
3643
+ $charPos = 0;
3644
+ $sstCount = count($this->_sst[$index]['fmtRuns']);
3645
+ for ($i = 0; $i <= $sstCount; ++$i) {
3646
+ if (isset($fmtRuns[$i])) {
3647
+ $text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, $fmtRuns[$i]['charPos'] - $charPos);
3648
+ $charPos = $fmtRuns[$i]['charPos'];
3649
+ } else {
3650
+ $text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, PHPExcel_Shared_String::CountCharacters($this->_sst[$index]['value']));
3651
+ }
3652
+
3653
+ if (PHPExcel_Shared_String::CountCharacters($text) > 0) {
3654
+ if ($i == 0) { // first text run, no style
3655
+ $richText->createText($text);
3656
+ } else {
3657
+ $textRun = $richText->createTextRun($text);
3658
+ if (isset($fmtRuns[$i - 1])) {
3659
+ if ($fmtRuns[$i - 1]['fontIndex'] < 4) {
3660
+ $fontIndex = $fmtRuns[$i - 1]['fontIndex'];
3661
+ } else {
3662
+ // this has to do with that index 4 is omitted in all BIFF versions for some strange reason
3663
+ // check the OpenOffice documentation of the FONT record
3664
+ $fontIndex = $fmtRuns[$i - 1]['fontIndex'] - 1;
3665
+ }
3666
+ $textRun->setFont(clone $this->_objFonts[$fontIndex]);
3667
+ }
3668
+ }
3669
+ }
3670
+ }
3671
+ $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3672
+ $cell->setValueExplicit($richText, PHPExcel_Cell_DataType::TYPE_STRING);
3673
+ } else {
3674
+ $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3675
+ $cell->setValueExplicit($this->_sst[$index]['value'], PHPExcel_Cell_DataType::TYPE_STRING);
3676
+ }
3677
+
3678
+ if (!$this->_readDataOnly) {
3679
+ // add style information
3680
+ $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3681
+ }
3682
+ }
3683
+ }
3684
+
3685
+
3686
+ /**
3687
+ * Read MULRK record
3688
+ * This record represents a cell range containing RK value
3689
+ * cells. All cells are located in the same row.
3690
+ *
3691
+ * -- "OpenOffice.org's Documentation of the Microsoft
3692
+ * Excel File Format"
3693
+ */
3694
+ private function _readMulRk()
3695
+ {
3696
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3697
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3698
+
3699
+ // move stream pointer to next record
3700
+ $this->_pos += 4 + $length;
3701
+
3702
+ // offset: 0; size: 2; index to row
3703
+ $row = self::_GetInt2d($recordData, 0);
3704
+
3705
+ // offset: 2; size: 2; index to first column
3706
+ $colFirst = self::_GetInt2d($recordData, 2);
3707
+
3708
+ // offset: var; size: 2; index to last column
3709
+ $colLast = self::_GetInt2d($recordData, $length - 2);
3710
+ $columns = $colLast - $colFirst + 1;
3711
+
3712
+ // offset within record data
3713
+ $offset = 4;
3714
+
3715
+ for ($i = 0; $i < $columns; ++$i) {
3716
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($colFirst + $i);
3717
+
3718
+ // Read cell?
3719
+ if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3720
+
3721
+ // offset: var; size: 2; index to XF record
3722
+ $xfIndex = self::_GetInt2d($recordData, $offset);
3723
+
3724
+ // offset: var; size: 4; RK value
3725
+ $numValue = self::_GetIEEE754(self::_GetInt4d($recordData, $offset + 2));
3726
+ $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3727
+ if (!$this->_readDataOnly) {
3728
+ // add style
3729
+ $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3730
+ }
3731
+
3732
+ // add cell value
3733
+ $cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
3734
+ }
3735
+
3736
+ $offset += 6;
3737
+ }
3738
+ }
3739
+
3740
+
3741
+ /**
3742
+ * Read NUMBER record
3743
+ * This record represents a cell that contains a
3744
+ * floating-point value.
3745
+ *
3746
+ * -- "OpenOffice.org's Documentation of the Microsoft
3747
+ * Excel File Format"
3748
+ */
3749
+ private function _readNumber()
3750
+ {
3751
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3752
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3753
+
3754
+ // move stream pointer to next record
3755
+ $this->_pos += 4 + $length;
3756
+
3757
+ // offset: 0; size: 2; index to row
3758
+ $row = self::_GetInt2d($recordData, 0);
3759
+
3760
+ // offset: 2; size 2; index to column
3761
+ $column = self::_GetInt2d($recordData, 2);
3762
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3763
+
3764
+ // Read cell?
3765
+ if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3766
+ // offset 4; size: 2; index to XF record
3767
+ $xfIndex = self::_GetInt2d($recordData, 4);
3768
+
3769
+ $numValue = self::_extractNumber(substr($recordData, 6, 8));
3770
+
3771
+ $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3772
+ if (!$this->_readDataOnly) {
3773
+ // add cell style
3774
+ $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3775
+ }
3776
+
3777
+ // add cell value
3778
+ $cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
3779
+ }
3780
+ }
3781
+
3782
+
3783
+ /**
3784
+ * Read FORMULA record + perhaps a following STRING record if formula result is a string
3785
+ * This record contains the token array and the result of a
3786
+ * formula cell.
3787
+ *
3788
+ * -- "OpenOffice.org's Documentation of the Microsoft
3789
+ * Excel File Format"
3790
+ */
3791
+ private function _readFormula()
3792
+ {
3793
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3794
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3795
+
3796
+ // move stream pointer to next record
3797
+ $this->_pos += 4 + $length;
3798
+
3799
+ // offset: 0; size: 2; row index
3800
+ $row = self::_GetInt2d($recordData, 0);
3801
+
3802
+ // offset: 2; size: 2; col index
3803
+ $column = self::_GetInt2d($recordData, 2);
3804
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3805
+
3806
+ // offset: 20: size: variable; formula structure
3807
+ $formulaStructure = substr($recordData, 20);
3808
+
3809
+ // offset: 14: size: 2; option flags, recalculate always, recalculate on open etc.
3810
+ $options = self::_GetInt2d($recordData, 14);
3811
+
3812
+ // bit: 0; mask: 0x0001; 1 = recalculate always
3813
+ // bit: 1; mask: 0x0002; 1 = calculate on open
3814
+ // bit: 2; mask: 0x0008; 1 = part of a shared formula
3815
+ $isPartOfSharedFormula = (bool) (0x0008 & $options);
3816
+
3817
+ // WARNING:
3818
+ // We can apparently not rely on $isPartOfSharedFormula. Even when $isPartOfSharedFormula = true
3819
+ // the formula data may be ordinary formula data, therefore we need to check
3820
+ // explicitly for the tExp token (0x01)
3821
+ $isPartOfSharedFormula = $isPartOfSharedFormula && ord($formulaStructure{2}) == 0x01;
3822
+
3823
+ if ($isPartOfSharedFormula) {
3824
+ // part of shared formula which means there will be a formula with a tExp token and nothing else
3825
+ // get the base cell, grab tExp token
3826
+ $baseRow = self::_GetInt2d($formulaStructure, 3);
3827
+ $baseCol = self::_GetInt2d($formulaStructure, 5);
3828
+ $this->_baseCell = PHPExcel_Cell::stringFromColumnIndex($baseCol). ($baseRow + 1);
3829
+ }
3830
+
3831
+ // Read cell?
3832
+ if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3833
+
3834
+ if ($isPartOfSharedFormula) {
3835
+ // formula is added to this cell after the sheet has been read
3836
+ $this->_sharedFormulaParts[$columnString . ($row + 1)] = $this->_baseCell;
3837
+ }
3838
+
3839
+ // offset: 16: size: 4; not used
3840
+
3841
+ // offset: 4; size: 2; XF index
3842
+ $xfIndex = self::_GetInt2d($recordData, 4);
3843
+
3844
+ // offset: 6; size: 8; result of the formula
3845
+ if ( (ord($recordData{6}) == 0)
3846
+ && (ord($recordData{12}) == 255)
3847
+ && (ord($recordData{13}) == 255) ) {
3848
+
3849
+ // String formula. Result follows in appended STRING record
3850
+ $dataType = PHPExcel_Cell_DataType::TYPE_STRING;
3851
+
3852
+ // read possible SHAREDFMLA record
3853
+ $code = self::_GetInt2d($this->_data, $this->_pos);
3854
+ if ($code == self::XLS_Type_SHAREDFMLA) {
3855
+ $this->_readSharedFmla();
3856
+ }
3857
+
3858
+ // read STRING record
3859
+ $value = $this->_readString();
3860
+
3861
+ } elseif ((ord($recordData{6}) == 1)
3862
+ && (ord($recordData{12}) == 255)
3863
+ && (ord($recordData{13}) == 255)) {
3864
+
3865
+ // Boolean formula. Result is in +2; 0=false, 1=true
3866
+ $dataType = PHPExcel_Cell_DataType::TYPE_BOOL;
3867
+ $value = (bool) ord($recordData{8});
3868
+
3869
+ } elseif ((ord($recordData{6}) == 2)
3870
+ && (ord($recordData{12}) == 255)
3871
+ && (ord($recordData{13}) == 255)) {
3872
+
3873
+ // Error formula. Error code is in +2
3874
+ $dataType = PHPExcel_Cell_DataType::TYPE_ERROR;
3875
+ $value = self::_mapErrorCode(ord($recordData{8}));
3876
+
3877
+ } elseif ((ord($recordData{6}) == 3)
3878
+ && (ord($recordData{12}) == 255)
3879
+ && (ord($recordData{13}) == 255)) {
3880
+
3881
+ // Formula result is a null string
3882
+ $dataType = PHPExcel_Cell_DataType::TYPE_NULL;
3883
+ $value = '';
3884
+
3885
+ } else {
3886
+
3887
+ // forumla result is a number, first 14 bytes like _NUMBER record
3888
+ $dataType = PHPExcel_Cell_DataType::TYPE_NUMERIC;
3889
+ $value = self::_extractNumber(substr($recordData, 6, 8));
3890
+
3891
+ }
3892
+
3893
+ $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3894
+ if (!$this->_readDataOnly) {
3895
+ // add cell style
3896
+ $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3897
+ }
3898
+
3899
+ // store the formula
3900
+ if (!$isPartOfSharedFormula) {
3901
+ // not part of shared formula
3902
+ // add cell value. If we can read formula, populate with formula, otherwise just used cached value
3903
+ try {
3904
+ if ($this->_version != self::XLS_BIFF8) {
3905
+ throw new PHPExcel_Reader_Exception('Not BIFF8. Can only read BIFF8 formulas');
3906
+ }
3907
+ $formula = $this->_getFormulaFromStructure($formulaStructure); // get formula in human language
3908
+ $cell->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
3909
+
3910
+ } catch (PHPExcel_Exception $e) {
3911
+ $cell->setValueExplicit($value, $dataType);
3912
+ }
3913
+ } else {
3914
+ if ($this->_version == self::XLS_BIFF8) {
3915
+ // do nothing at this point, formula id added later in the code
3916
+ } else {
3917
+ $cell->setValueExplicit($value, $dataType);
3918
+ }
3919
+ }
3920
+
3921
+ // store the cached calculated value
3922
+ $cell->setCalculatedValue($value);
3923
+ }
3924
+ }
3925
+
3926
+
3927
+ /**
3928
+ * Read a SHAREDFMLA record. This function just stores the binary shared formula in the reader,
3929
+ * which usually contains relative references.
3930
+ * These will be used to construct the formula in each shared formula part after the sheet is read.
3931
+ */
3932
+ private function _readSharedFmla()
3933
+ {
3934
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3935
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3936
+
3937
+ // move stream pointer to next record
3938
+ $this->_pos += 4 + $length;
3939
+
3940
+ // offset: 0, size: 6; cell range address of the area used by the shared formula, not used for anything
3941
+ $cellRange = substr($recordData, 0, 6);
3942
+ $cellRange = $this->_readBIFF5CellRangeAddressFixed($cellRange); // note: even BIFF8 uses BIFF5 syntax
3943
+
3944
+ // offset: 6, size: 1; not used
3945
+
3946
+ // offset: 7, size: 1; number of existing FORMULA records for this shared formula
3947
+ $no = ord($recordData{7});
3948
+
3949
+ // offset: 8, size: var; Binary token array of the shared formula
3950
+ $formula = substr($recordData, 8);
3951
+
3952
+ // at this point we only store the shared formula for later use
3953
+ $this->_sharedFormulas[$this->_baseCell] = $formula;
3954
+
3955
+ }
3956
+
3957
+
3958
+ /**
3959
+ * Read a STRING record from current stream position and advance the stream pointer to next record
3960
+ * This record is used for storing result from FORMULA record when it is a string, and
3961
+ * it occurs directly after the FORMULA record
3962
+ *
3963
+ * @return string The string contents as UTF-8
3964
+ */
3965
+ private function _readString()
3966
+ {
3967
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3968
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3969
+
3970
+ // move stream pointer to next record
3971
+ $this->_pos += 4 + $length;
3972
+
3973
+ if ($this->_version == self::XLS_BIFF8) {
3974
+ $string = self::_readUnicodeStringLong($recordData);
3975
+ $value = $string['value'];
3976
+ } else {
3977
+ $string = $this->_readByteStringLong($recordData);
3978
+ $value = $string['value'];
3979
+ }
3980
+
3981
+ return $value;
3982
+ }
3983
+
3984
+
3985
+ /**
3986
+ * Read BOOLERR record
3987
+ * This record represents a Boolean value or error value
3988
+ * cell.
3989
+ *
3990
+ * -- "OpenOffice.org's Documentation of the Microsoft
3991
+ * Excel File Format"
3992
+ */
3993
+ private function _readBoolErr()
3994
+ {
3995
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
3996
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
3997
+
3998
+ // move stream pointer to next record
3999
+ $this->_pos += 4 + $length;
4000
+
4001
+ // offset: 0; size: 2; row index
4002
+ $row = self::_GetInt2d($recordData, 0);
4003
+
4004
+ // offset: 2; size: 2; column index
4005
+ $column = self::_GetInt2d($recordData, 2);
4006
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
4007
+
4008
+ // Read cell?
4009
+ if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
4010
+ // offset: 4; size: 2; index to XF record
4011
+ $xfIndex = self::_GetInt2d($recordData, 4);
4012
+
4013
+ // offset: 6; size: 1; the boolean value or error value
4014
+ $boolErr = ord($recordData{6});
4015
+
4016
+ // offset: 7; size: 1; 0=boolean; 1=error
4017
+ $isError = ord($recordData{7});
4018
+
4019
+ $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
4020
+ switch ($isError) {
4021
+ case 0: // boolean
4022
+ $value = (bool) $boolErr;
4023
+
4024
+ // add cell value
4025
+ $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_BOOL);
4026
+ break;
4027
+
4028
+ case 1: // error type
4029
+ $value = self::_mapErrorCode($boolErr);
4030
+
4031
+ // add cell value
4032
+ $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_ERROR);
4033
+ break;
4034
+ }
4035
+
4036
+ if (!$this->_readDataOnly) {
4037
+ // add cell style
4038
+ $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
4039
+ }
4040
+ }
4041
+ }
4042
+
4043
+
4044
+ /**
4045
+ * Read MULBLANK record
4046
+ * This record represents a cell range of empty cells. All
4047
+ * cells are located in the same row
4048
+ *
4049
+ * -- "OpenOffice.org's Documentation of the Microsoft
4050
+ * Excel File Format"
4051
+ */
4052
+ private function _readMulBlank()
4053
+ {
4054
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4055
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4056
+
4057
+ // move stream pointer to next record
4058
+ $this->_pos += 4 + $length;
4059
+
4060
+ // offset: 0; size: 2; index to row
4061
+ $row = self::_GetInt2d($recordData, 0);
4062
+
4063
+ // offset: 2; size: 2; index to first column
4064
+ $fc = self::_GetInt2d($recordData, 2);
4065
+
4066
+ // offset: 4; size: 2 x nc; list of indexes to XF records
4067
+ // add style information
4068
+ if (!$this->_readDataOnly) {
4069
+ for ($i = 0; $i < $length / 2 - 3; ++$i) {
4070
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($fc + $i);
4071
+
4072
+ // Read cell?
4073
+ if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
4074
+ $xfIndex = self::_GetInt2d($recordData, 4 + 2 * $i);
4075
+ $this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
4076
+ }
4077
+ }
4078
+ }
4079
+
4080
+ // offset: 6; size 2; index to last column (not needed)
4081
+ }
4082
+
4083
+
4084
+ /**
4085
+ * Read LABEL record
4086
+ * This record represents a cell that contains a string. In
4087
+ * BIFF8 it is usually replaced by the LABELSST record.
4088
+ * Excel still uses this record, if it copies unformatted
4089
+ * text cells to the clipboard.
4090
+ *
4091
+ * -- "OpenOffice.org's Documentation of the Microsoft
4092
+ * Excel File Format"
4093
+ */
4094
+ private function _readLabel()
4095
+ {
4096
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4097
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4098
+
4099
+ // move stream pointer to next record
4100
+ $this->_pos += 4 + $length;
4101
+
4102
+ // offset: 0; size: 2; index to row
4103
+ $row = self::_GetInt2d($recordData, 0);
4104
+
4105
+ // offset: 2; size: 2; index to column
4106
+ $column = self::_GetInt2d($recordData, 2);
4107
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
4108
+
4109
+ // Read cell?
4110
+ if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
4111
+ // offset: 4; size: 2; XF index
4112
+ $xfIndex = self::_GetInt2d($recordData, 4);
4113
+
4114
+ // add cell value
4115
+ // todo: what if string is very long? continue record
4116
+ if ($this->_version == self::XLS_BIFF8) {
4117
+ $string = self::_readUnicodeStringLong(substr($recordData, 6));
4118
+ $value = $string['value'];
4119
+ } else {
4120
+ $string = $this->_readByteStringLong(substr($recordData, 6));
4121
+ $value = $string['value'];
4122
+ }
4123
+ $cell = $this->_phpSheet->getCell($columnString . ($row + 1));
4124
+ $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
4125
+
4126
+ if (!$this->_readDataOnly) {
4127
+ // add cell style
4128
+ $cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
4129
+ }
4130
+ }
4131
+ }
4132
+
4133
+
4134
+ /**
4135
+ * Read BLANK record
4136
+ */
4137
+ private function _readBlank()
4138
+ {
4139
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4140
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4141
+
4142
+ // move stream pointer to next record
4143
+ $this->_pos += 4 + $length;
4144
+
4145
+ // offset: 0; size: 2; row index
4146
+ $row = self::_GetInt2d($recordData, 0);
4147
+
4148
+ // offset: 2; size: 2; col index
4149
+ $col = self::_GetInt2d($recordData, 2);
4150
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($col);
4151
+
4152
+ // Read cell?
4153
+ if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
4154
+ // offset: 4; size: 2; XF index
4155
+ $xfIndex = self::_GetInt2d($recordData, 4);
4156
+
4157
+ // add style information
4158
+ if (!$this->_readDataOnly) {
4159
+ $this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
4160
+ }
4161
+ }
4162
+
4163
+ }
4164
+
4165
+
4166
+ /**
4167
+ * Read MSODRAWING record
4168
+ */
4169
+ private function _readMsoDrawing()
4170
+ {
4171
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4172
+
4173
+ // get spliced record data
4174
+ $splicedRecordData = $this->_getSplicedRecordData();
4175
+ $recordData = $splicedRecordData['recordData'];
4176
+
4177
+ $this->_drawingData .= $recordData;
4178
+ }
4179
+
4180
+
4181
+ /**
4182
+ * Read OBJ record
4183
+ */
4184
+ private function _readObj()
4185
+ {
4186
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4187
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4188
+
4189
+ // move stream pointer to next record
4190
+ $this->_pos += 4 + $length;
4191
+
4192
+ if ($this->_readDataOnly || $this->_version != self::XLS_BIFF8) {
4193
+ return;
4194
+ }
4195
+
4196
+ // recordData consists of an array of subrecords looking like this:
4197
+ // ft: 2 bytes; ftCmo type (0x15)
4198
+ // cb: 2 bytes; size in bytes of ftCmo data
4199
+ // ot: 2 bytes; Object Type
4200
+ // id: 2 bytes; Object id number
4201
+ // grbit: 2 bytes; Option Flags
4202
+ // data: var; subrecord data
4203
+
4204
+ // for now, we are just interested in the second subrecord containing the object type
4205
+ $ftCmoType = self::_GetInt2d($recordData, 0);
4206
+ $cbCmoSize = self::_GetInt2d($recordData, 2);
4207
+ $otObjType = self::_GetInt2d($recordData, 4);
4208
+ $idObjID = self::_GetInt2d($recordData, 6);
4209
+ $grbitOpts = self::_GetInt2d($recordData, 6);
4210
+
4211
+ $this->_objs[] = array(
4212
+ 'ftCmoType' => $ftCmoType,
4213
+ 'cbCmoSize' => $cbCmoSize,
4214
+ 'otObjType' => $otObjType,
4215
+ 'idObjID' => $idObjID,
4216
+ 'grbitOpts' => $grbitOpts
4217
+ );
4218
+ $this->textObjRef = $idObjID;
4219
+
4220
+ // echo '<b>_readObj()</b><br />';
4221
+ // var_dump(end($this->_objs));
4222
+ // echo '<br />';
4223
+ }
4224
+
4225
+
4226
+ /**
4227
+ * Read WINDOW2 record
4228
+ */
4229
+ private function _readWindow2()
4230
+ {
4231
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4232
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4233
+
4234
+ // move stream pointer to next record
4235
+ $this->_pos += 4 + $length;
4236
+
4237
+ // offset: 0; size: 2; option flags
4238
+ $options = self::_GetInt2d($recordData, 0);
4239
+
4240
+ // offset: 2; size: 2; index to first visible row
4241
+ $firstVisibleRow = self::_GetInt2d($recordData, 2);
4242
+
4243
+ // offset: 4; size: 2; index to first visible colum
4244
+ $firstVisibleColumn = self::_GetInt2d($recordData, 4);
4245
+ if ($this->_version === self::XLS_BIFF8) {
4246
+ // offset: 8; size: 2; not used
4247
+ // offset: 10; size: 2; cached magnification factor in page break preview (in percent); 0 = Default (60%)
4248
+ // offset: 12; size: 2; cached magnification factor in normal view (in percent); 0 = Default (100%)
4249
+ // offset: 14; size: 4; not used
4250
+ $zoomscaleInPageBreakPreview = self::_GetInt2d($recordData, 10);
4251
+ if ($zoomscaleInPageBreakPreview === 0) $zoomscaleInPageBreakPreview = 60;
4252
+ $zoomscaleInNormalView = self::_GetInt2d($recordData, 12);
4253
+ if ($zoomscaleInNormalView === 0) $zoomscaleInNormalView = 100;
4254
+ }
4255
+
4256
+ // bit: 1; mask: 0x0002; 0 = do not show gridlines, 1 = show gridlines
4257
+ $showGridlines = (bool) ((0x0002 & $options) >> 1);
4258
+ $this->_phpSheet->setShowGridlines($showGridlines);
4259
+
4260
+ // bit: 2; mask: 0x0004; 0 = do not show headers, 1 = show headers
4261
+ $showRowColHeaders = (bool) ((0x0004 & $options) >> 2);
4262
+ $this->_phpSheet->setShowRowColHeaders($showRowColHeaders);
4263
+
4264
+ // bit: 3; mask: 0x0008; 0 = panes are not frozen, 1 = panes are frozen
4265
+ $this->_frozen = (bool) ((0x0008 & $options) >> 3);
4266
+
4267
+ // bit: 6; mask: 0x0040; 0 = columns from left to right, 1 = columns from right to left
4268
+ $this->_phpSheet->setRightToLeft((bool)((0x0040 & $options) >> 6));
4269
+
4270
+ // bit: 10; mask: 0x0400; 0 = sheet not active, 1 = sheet active
4271
+ $isActive = (bool) ((0x0400 & $options) >> 10);
4272
+ if ($isActive) {
4273
+ $this->_phpExcel->setActiveSheetIndex($this->_phpExcel->getIndex($this->_phpSheet));
4274
+ }
4275
+
4276
+ // bit: 11; mask: 0x0800; 0 = normal view, 1 = page break view
4277
+ $isPageBreakPreview = (bool) ((0x0800 & $options) >> 11);
4278
+
4279
+ //FIXME: set $firstVisibleRow and $firstVisibleColumn
4280
+
4281
+ if ($this->_phpSheet->getSheetView()->getView() !== PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_LAYOUT) {
4282
+ //NOTE: this setting is inferior to page layout view(Excel2007-)
4283
+ $view = $isPageBreakPreview? PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_BREAK_PREVIEW :
4284
+ PHPExcel_Worksheet_SheetView::SHEETVIEW_NORMAL;
4285
+ $this->_phpSheet->getSheetView()->setView($view);
4286
+ if ($this->_version === self::XLS_BIFF8) {
4287
+ $zoomScale = $isPageBreakPreview? $zoomscaleInPageBreakPreview : $zoomscaleInNormalView;
4288
+ $this->_phpSheet->getSheetView()->setZoomScale($zoomScale);
4289
+ $this->_phpSheet->getSheetView()->setZoomScaleNormal($zoomscaleInNormalView);
4290
+ }
4291
+ }
4292
+ }
4293
+
4294
+ /**
4295
+ * Read PLV Record(Created by Excel2007 or upper)
4296
+ */
4297
+ private function _readPageLayoutView(){
4298
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4299
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4300
+
4301
+ // move stream pointer to next record
4302
+ $this->_pos += 4 + $length;
4303
+
4304
+ //var_dump(unpack("vrt/vgrbitFrt/V2reserved/vwScalePLV/vgrbit", $recordData));
4305
+
4306
+ // offset: 0; size: 2; rt
4307
+ //->ignore
4308
+ $rt = self::_GetInt2d($recordData, 0);
4309
+ // offset: 2; size: 2; grbitfr
4310
+ //->ignore
4311
+ $grbitFrt = self::_GetInt2d($recordData, 2);
4312
+ // offset: 4; size: 8; reserved
4313
+ //->ignore
4314
+
4315
+ // offset: 12; size 2; zoom scale
4316
+ $wScalePLV = self::_GetInt2d($recordData, 12);
4317
+ // offset: 14; size 2; grbit
4318
+ $grbit = self::_GetInt2d($recordData, 14);
4319
+
4320
+ // decomprise grbit
4321
+ $fPageLayoutView = $grbit & 0x01;
4322
+ $fRulerVisible = ($grbit >> 1) & 0x01; //no support
4323
+ $fWhitespaceHidden = ($grbit >> 3) & 0x01; //no support
4324
+
4325
+ if ($fPageLayoutView === 1) {
4326
+ $this->_phpSheet->getSheetView()->setView(PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_LAYOUT);
4327
+ $this->_phpSheet->getSheetView()->setZoomScale($wScalePLV); //set by Excel2007 only if SHEETVIEW_PAGE_LAYOUT
4328
+ }
4329
+ //otherwise, we cannot know whether SHEETVIEW_PAGE_LAYOUT or SHEETVIEW_PAGE_BREAK_PREVIEW.
4330
+ }
4331
+
4332
+ /**
4333
+ * Read SCL record
4334
+ */
4335
+ private function _readScl()
4336
+ {
4337
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4338
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4339
+
4340
+ // move stream pointer to next record
4341
+ $this->_pos += 4 + $length;
4342
+
4343
+ // offset: 0; size: 2; numerator of the view magnification
4344
+ $numerator = self::_GetInt2d($recordData, 0);
4345
+
4346
+ // offset: 2; size: 2; numerator of the view magnification
4347
+ $denumerator = self::_GetInt2d($recordData, 2);
4348
+
4349
+ // set the zoom scale (in percent)
4350
+ $this->_phpSheet->getSheetView()->setZoomScale($numerator * 100 / $denumerator);
4351
+ }
4352
+
4353
+
4354
+ /**
4355
+ * Read PANE record
4356
+ */
4357
+ private function _readPane()
4358
+ {
4359
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4360
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4361
+
4362
+ // move stream pointer to next record
4363
+ $this->_pos += 4 + $length;
4364
+
4365
+ if (!$this->_readDataOnly) {
4366
+ // offset: 0; size: 2; position of vertical split
4367
+ $px = self::_GetInt2d($recordData, 0);
4368
+
4369
+ // offset: 2; size: 2; position of horizontal split
4370
+ $py = self::_GetInt2d($recordData, 2);
4371
+
4372
+ if ($this->_frozen) {
4373
+ // frozen panes
4374
+ $this->_phpSheet->freezePane(PHPExcel_Cell::stringFromColumnIndex($px) . ($py + 1));
4375
+ } else {
4376
+ // unfrozen panes; split windows; not supported by PHPExcel core
4377
+ }
4378
+ }
4379
+ }
4380
+
4381
+
4382
+ /**
4383
+ * Read SELECTION record. There is one such record for each pane in the sheet.
4384
+ */
4385
+ private function _readSelection()
4386
+ {
4387
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4388
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4389
+
4390
+ // move stream pointer to next record
4391
+ $this->_pos += 4 + $length;
4392
+
4393
+ if (!$this->_readDataOnly) {
4394
+ // offset: 0; size: 1; pane identifier
4395
+ $paneId = ord($recordData{0});
4396
+
4397
+ // offset: 1; size: 2; index to row of the active cell
4398
+ $r = self::_GetInt2d($recordData, 1);
4399
+
4400
+ // offset: 3; size: 2; index to column of the active cell
4401
+ $c = self::_GetInt2d($recordData, 3);
4402
+
4403
+ // offset: 5; size: 2; index into the following cell range list to the
4404
+ // entry that contains the active cell
4405
+ $index = self::_GetInt2d($recordData, 5);
4406
+
4407
+ // offset: 7; size: var; cell range address list containing all selected cell ranges
4408
+ $data = substr($recordData, 7);
4409
+ $cellRangeAddressList = $this->_readBIFF5CellRangeAddressList($data); // note: also BIFF8 uses BIFF5 syntax
4410
+
4411
+ $selectedCells = $cellRangeAddressList['cellRangeAddresses'][0];
4412
+
4413
+ // first row '1' + last row '16384' indicates that full column is selected (apparently also in BIFF8!)
4414
+ if (preg_match('/^([A-Z]+1\:[A-Z]+)16384$/', $selectedCells)) {
4415
+ $selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)16384$/', '${1}1048576', $selectedCells);
4416
+ }
4417
+
4418
+ // first row '1' + last row '65536' indicates that full column is selected
4419
+ if (preg_match('/^([A-Z]+1\:[A-Z]+)65536$/', $selectedCells)) {
4420
+ $selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)65536$/', '${1}1048576', $selectedCells);
4421
+ }
4422
+
4423
+ // first column 'A' + last column 'IV' indicates that full row is selected
4424
+ if (preg_match('/^(A[0-9]+\:)IV([0-9]+)$/', $selectedCells)) {
4425
+ $selectedCells = preg_replace('/^(A[0-9]+\:)IV([0-9]+)$/', '${1}XFD${2}', $selectedCells);
4426
+ }
4427
+
4428
+ $this->_phpSheet->setSelectedCells($selectedCells);
4429
+ }
4430
+ }
4431
+
4432
+
4433
+ private function _includeCellRangeFiltered($cellRangeAddress)
4434
+ {
4435
+ $includeCellRange = true;
4436
+ if ($this->getReadFilter() !== NULL) {
4437
+ $includeCellRange = false;
4438
+ $rangeBoundaries = PHPExcel_Cell::getRangeBoundaries($cellRangeAddress);
4439
+ $rangeBoundaries[1][0]++;
4440
+ for ($row = $rangeBoundaries[0][1]; $row <= $rangeBoundaries[1][1]; $row++) {
4441
+ for ($column = $rangeBoundaries[0][0]; $column != $rangeBoundaries[1][0]; $column++) {
4442
+ if ($this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle())) {
4443
+ $includeCellRange = true;
4444
+ break 2;
4445
+ }
4446
+ }
4447
+ }
4448
+ }
4449
+ return $includeCellRange;
4450
+ }
4451
+
4452
+
4453
+ /**
4454
+ * MERGEDCELLS
4455
+ *
4456
+ * This record contains the addresses of merged cell ranges
4457
+ * in the current sheet.
4458
+ *
4459
+ * -- "OpenOffice.org's Documentation of the Microsoft
4460
+ * Excel File Format"
4461
+ */
4462
+ private function _readMergedCells()
4463
+ {
4464
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4465
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4466
+
4467
+ // move stream pointer to next record
4468
+ $this->_pos += 4 + $length;
4469
+
4470
+ if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
4471
+ $cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($recordData);
4472
+ foreach ($cellRangeAddressList['cellRangeAddresses'] as $cellRangeAddress) {
4473
+ if ((strpos($cellRangeAddress,':') !== FALSE) &&
4474
+ ($this->_includeCellRangeFiltered($cellRangeAddress))) {
4475
+ $this->_phpSheet->mergeCells($cellRangeAddress);
4476
+ }
4477
+ }
4478
+ }
4479
+ }
4480
+
4481
+
4482
+ /**
4483
+ * Read HYPERLINK record
4484
+ */
4485
+ private function _readHyperLink()
4486
+ {
4487
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4488
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4489
+
4490
+ // move stream pointer forward to next record
4491
+ $this->_pos += 4 + $length;
4492
+
4493
+ if (!$this->_readDataOnly) {
4494
+ // offset: 0; size: 8; cell range address of all cells containing this hyperlink
4495
+ try {
4496
+ $cellRange = $this->_readBIFF8CellRangeAddressFixed($recordData, 0, 8);
4497
+ } catch (PHPExcel_Exception $e) {
4498
+ return;
4499
+ }
4500
+
4501
+ // offset: 8, size: 16; GUID of StdLink
4502
+
4503
+ // offset: 24, size: 4; unknown value
4504
+
4505
+ // offset: 28, size: 4; option flags
4506
+
4507
+ // bit: 0; mask: 0x00000001; 0 = no link or extant, 1 = file link or URL
4508
+ $isFileLinkOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 0;
4509
+
4510
+ // bit: 1; mask: 0x00000002; 0 = relative path, 1 = absolute path or URL
4511
+ $isAbsPathOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 1;
4512
+
4513
+ // bit: 2 (and 4); mask: 0x00000014; 0 = no description
4514
+ $hasDesc = (0x00000014 & self::_GetInt2d($recordData, 28)) >> 2;
4515
+
4516
+ // bit: 3; mask: 0x00000008; 0 = no text, 1 = has text
4517
+ $hasText = (0x00000008 & self::_GetInt2d($recordData, 28)) >> 3;
4518
+
4519
+ // bit: 7; mask: 0x00000080; 0 = no target frame, 1 = has target frame
4520
+ $hasFrame = (0x00000080 & self::_GetInt2d($recordData, 28)) >> 7;
4521
+
4522
+ // bit: 8; mask: 0x00000100; 0 = file link or URL, 1 = UNC path (inc. server name)
4523
+ $isUNC = (0x00000100 & self::_GetInt2d($recordData, 28)) >> 8;
4524
+
4525
+ // offset within record data
4526
+ $offset = 32;
4527
+
4528
+ if ($hasDesc) {
4529
+ // offset: 32; size: var; character count of description text
4530
+ $dl = self::_GetInt4d($recordData, 32);
4531
+ // offset: 36; size: var; character array of description text, no Unicode string header, always 16-bit characters, zero terminated
4532
+ $desc = self::_encodeUTF16(substr($recordData, 36, 2 * ($dl - 1)), false);
4533
+ $offset += 4 + 2 * $dl;
4534
+ }
4535
+ if ($hasFrame) {
4536
+ $fl = self::_GetInt4d($recordData, $offset);
4537
+ $offset += 4 + 2 * $fl;
4538
+ }
4539
+
4540
+ // detect type of hyperlink (there are 4 types)
4541
+ $hyperlinkType = null;
4542
+
4543
+ if ($isUNC) {
4544
+ $hyperlinkType = 'UNC';
4545
+ } else if (!$isFileLinkOrUrl) {
4546
+ $hyperlinkType = 'workbook';
4547
+ } else if (ord($recordData{$offset}) == 0x03) {
4548
+ $hyperlinkType = 'local';
4549
+ } else if (ord($recordData{$offset}) == 0xE0) {
4550
+ $hyperlinkType = 'URL';
4551
+ }
4552
+
4553
+ switch ($hyperlinkType) {
4554
+ case 'URL':
4555
+ // section 5.58.2: Hyperlink containing a URL
4556
+ // e.g. http://example.org/index.php
4557
+
4558
+ // offset: var; size: 16; GUID of URL Moniker
4559
+ $offset += 16;
4560
+ // offset: var; size: 4; size (in bytes) of character array of the URL including trailing zero word
4561
+ $us = self::_GetInt4d($recordData, $offset);
4562
+ $offset += 4;
4563
+ // offset: var; size: $us; character array of the URL, no Unicode string header, always 16-bit characters, zero-terminated
4564
+ $url = self::_encodeUTF16(substr($recordData, $offset, $us - 2), false);
4565
+ $nullOffset = strpos($url, 0x00);
4566
+ if ($nullOffset)
4567
+ $url = substr($url,0,$nullOffset);
4568
+ $url .= $hasText ? '#' : '';
4569
+ $offset += $us;
4570
+ break;
4571
+
4572
+ case 'local':
4573
+ // section 5.58.3: Hyperlink to local file
4574
+ // examples:
4575
+ // mydoc.txt
4576
+ // ../../somedoc.xls#Sheet!A1
4577
+
4578
+ // offset: var; size: 16; GUI of File Moniker
4579
+ $offset += 16;
4580
+
4581
+ // offset: var; size: 2; directory up-level count.
4582
+ $upLevelCount = self::_GetInt2d($recordData, $offset);
4583
+ $offset += 2;
4584
+
4585
+ // offset: var; size: 4; character count of the shortened file path and name, including trailing zero word
4586
+ $sl = self::_GetInt4d($recordData, $offset);
4587
+ $offset += 4;
4588
+
4589
+ // offset: var; size: sl; character array of the shortened file path and name in 8.3-DOS-format (compressed Unicode string)
4590
+ $shortenedFilePath = substr($recordData, $offset, $sl);
4591
+ $shortenedFilePath = self::_encodeUTF16($shortenedFilePath, true);
4592
+ $shortenedFilePath = substr($shortenedFilePath, 0, -1); // remove trailing zero
4593
+
4594
+ $offset += $sl;
4595
+
4596
+ // offset: var; size: 24; unknown sequence
4597
+ $offset += 24;
4598
+
4599
+ // extended file path
4600
+ // offset: var; size: 4; size of the following file link field including string lenth mark
4601
+ $sz = self::_GetInt4d($recordData, $offset);
4602
+ $offset += 4;
4603
+
4604
+ // only present if $sz > 0
4605
+ if ($sz > 0) {
4606
+ // offset: var; size: 4; size of the character array of the extended file path and name
4607
+ $xl = self::_GetInt4d($recordData, $offset);
4608
+ $offset += 4;
4609
+
4610
+ // offset: var; size 2; unknown
4611
+ $offset += 2;
4612
+
4613
+ // offset: var; size $xl; character array of the extended file path and name.
4614
+ $extendedFilePath = substr($recordData, $offset, $xl);
4615
+ $extendedFilePath = self::_encodeUTF16($extendedFilePath, false);
4616
+ $offset += $xl;
4617
+ }
4618
+
4619
+ // construct the path
4620
+ $url = str_repeat('..\\', $upLevelCount);
4621
+ $url .= ($sz > 0) ?
4622
+ $extendedFilePath : $shortenedFilePath; // use extended path if available
4623
+ $url .= $hasText ? '#' : '';
4624
+
4625
+ break;
4626
+
4627
+
4628
+ case 'UNC':
4629
+ // section 5.58.4: Hyperlink to a File with UNC (Universal Naming Convention) Path
4630
+ // todo: implement
4631
+ return;
4632
+
4633
+ case 'workbook':
4634
+ // section 5.58.5: Hyperlink to the Current Workbook
4635
+ // e.g. Sheet2!B1:C2, stored in text mark field
4636
+ $url = 'sheet://';
4637
+ break;
4638
+
4639
+ default:
4640
+ return;
4641
+
4642
+ }
4643
+
4644
+ if ($hasText) {
4645
+ // offset: var; size: 4; character count of text mark including trailing zero word
4646
+ $tl = self::_GetInt4d($recordData, $offset);
4647
+ $offset += 4;
4648
+ // offset: var; size: var; character array of the text mark without the # sign, no Unicode header, always 16-bit characters, zero-terminated
4649
+ $text = self::_encodeUTF16(substr($recordData, $offset, 2 * ($tl - 1)), false);
4650
+ $url .= $text;
4651
+ }
4652
+
4653
+ // apply the hyperlink to all the relevant cells
4654
+ foreach (PHPExcel_Cell::extractAllCellReferencesInRange($cellRange) as $coordinate) {
4655
+ $this->_phpSheet->getCell($coordinate)->getHyperLink()->setUrl($url);
4656
+ }
4657
+ }
4658
+ }
4659
+
4660
+
4661
+ /**
4662
+ * Read DATAVALIDATIONS record
4663
+ */
4664
+ private function _readDataValidations()
4665
+ {
4666
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4667
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4668
+
4669
+ // move stream pointer forward to next record
4670
+ $this->_pos += 4 + $length;
4671
+ }
4672
+
4673
+
4674
+ /**
4675
+ * Read DATAVALIDATION record
4676
+ */
4677
+ private function _readDataValidation()
4678
+ {
4679
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4680
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4681
+
4682
+ // move stream pointer forward to next record
4683
+ $this->_pos += 4 + $length;
4684
+
4685
+ if ($this->_readDataOnly) {
4686
+ return;
4687
+ }
4688
+
4689
+ // offset: 0; size: 4; Options
4690
+ $options = self::_GetInt4d($recordData, 0);
4691
+
4692
+ // bit: 0-3; mask: 0x0000000F; type
4693
+ $type = (0x0000000F & $options) >> 0;
4694
+ switch ($type) {
4695
+ case 0x00: $type = PHPExcel_Cell_DataValidation::TYPE_NONE; break;
4696
+ case 0x01: $type = PHPExcel_Cell_DataValidation::TYPE_WHOLE; break;
4697
+ case 0x02: $type = PHPExcel_Cell_DataValidation::TYPE_DECIMAL; break;
4698
+ case 0x03: $type = PHPExcel_Cell_DataValidation::TYPE_LIST; break;
4699
+ case 0x04: $type = PHPExcel_Cell_DataValidation::TYPE_DATE; break;
4700
+ case 0x05: $type = PHPExcel_Cell_DataValidation::TYPE_TIME; break;
4701
+ case 0x06: $type = PHPExcel_Cell_DataValidation::TYPE_TEXTLENGTH; break;
4702
+ case 0x07: $type = PHPExcel_Cell_DataValidation::TYPE_CUSTOM; break;
4703
+ }
4704
+
4705
+ // bit: 4-6; mask: 0x00000070; error type
4706
+ $errorStyle = (0x00000070 & $options) >> 4;
4707
+ switch ($errorStyle) {
4708
+ case 0x00: $errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP; break;
4709
+ case 0x01: $errorStyle = PHPExcel_Cell_DataValidation::STYLE_WARNING; break;
4710
+ case 0x02: $errorStyle = PHPExcel_Cell_DataValidation::STYLE_INFORMATION; break;
4711
+ }
4712
+
4713
+ // bit: 7; mask: 0x00000080; 1= formula is explicit (only applies to list)
4714
+ // I have only seen cases where this is 1
4715
+ $explicitFormula = (0x00000080 & $options) >> 7;
4716
+
4717
+ // bit: 8; mask: 0x00000100; 1= empty cells allowed
4718
+ $allowBlank = (0x00000100 & $options) >> 8;
4719
+
4720
+ // bit: 9; mask: 0x00000200; 1= suppress drop down arrow in list type validity
4721
+ $suppressDropDown = (0x00000200 & $options) >> 9;
4722
+
4723
+ // bit: 18; mask: 0x00040000; 1= show prompt box if cell selected
4724
+ $showInputMessage = (0x00040000 & $options) >> 18;
4725
+
4726
+ // bit: 19; mask: 0x00080000; 1= show error box if invalid values entered
4727
+ $showErrorMessage = (0x00080000 & $options) >> 19;
4728
+
4729
+ // bit: 20-23; mask: 0x00F00000; condition operator
4730
+ $operator = (0x00F00000 & $options) >> 20;
4731
+ switch ($operator) {
4732
+ case 0x00: $operator = PHPExcel_Cell_DataValidation::OPERATOR_BETWEEN ; break;
4733
+ case 0x01: $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTBETWEEN ; break;
4734
+ case 0x02: $operator = PHPExcel_Cell_DataValidation::OPERATOR_EQUAL ; break;
4735
+ case 0x03: $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTEQUAL ; break;
4736
+ case 0x04: $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHAN ; break;
4737
+ case 0x05: $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHAN ; break;
4738
+ case 0x06: $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHANOREQUAL; break;
4739
+ case 0x07: $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHANOREQUAL ; break;
4740
+ }
4741
+
4742
+ // offset: 4; size: var; title of the prompt box
4743
+ $offset = 4;
4744
+ $string = self::_readUnicodeStringLong(substr($recordData, $offset));
4745
+ $promptTitle = $string['value'] !== chr(0) ?
4746
+ $string['value'] : '';
4747
+ $offset += $string['size'];
4748
+
4749
+ // offset: var; size: var; title of the error box
4750
+ $string = self::_readUnicodeStringLong(substr($recordData, $offset));
4751
+ $errorTitle = $string['value'] !== chr(0) ?
4752
+ $string['value'] : '';
4753
+ $offset += $string['size'];
4754
+
4755
+ // offset: var; size: var; text of the prompt box
4756
+ $string = self::_readUnicodeStringLong(substr($recordData, $offset));
4757
+ $prompt = $string['value'] !== chr(0) ?
4758
+ $string['value'] : '';
4759
+ $offset += $string['size'];
4760
+
4761
+ // offset: var; size: var; text of the error box
4762
+ $string = self::_readUnicodeStringLong(substr($recordData, $offset));
4763
+ $error = $string['value'] !== chr(0) ?
4764
+ $string['value'] : '';
4765
+ $offset += $string['size'];
4766
+
4767
+ // offset: var; size: 2; size of the formula data for the first condition
4768
+ $sz1 = self::_GetInt2d($recordData, $offset);
4769
+ $offset += 2;
4770
+
4771
+ // offset: var; size: 2; not used
4772
+ $offset += 2;
4773
+
4774
+ // offset: var; size: $sz1; formula data for first condition (without size field)
4775
+ $formula1 = substr($recordData, $offset, $sz1);
4776
+ $formula1 = pack('v', $sz1) . $formula1; // prepend the length
4777
+ try {
4778
+ $formula1 = $this->_getFormulaFromStructure($formula1);
4779
+
4780
+ // in list type validity, null characters are used as item separators
4781
+ if ($type == PHPExcel_Cell_DataValidation::TYPE_LIST) {
4782
+ $formula1 = str_replace(chr(0), ',', $formula1);
4783
+ }
4784
+ } catch (PHPExcel_Exception $e) {
4785
+ return;
4786
+ }
4787
+ $offset += $sz1;
4788
+
4789
+ // offset: var; size: 2; size of the formula data for the first condition
4790
+ $sz2 = self::_GetInt2d($recordData, $offset);
4791
+ $offset += 2;
4792
+
4793
+ // offset: var; size: 2; not used
4794
+ $offset += 2;
4795
+
4796
+ // offset: var; size: $sz2; formula data for second condition (without size field)
4797
+ $formula2 = substr($recordData, $offset, $sz2);
4798
+ $formula2 = pack('v', $sz2) . $formula2; // prepend the length
4799
+ try {
4800
+ $formula2 = $this->_getFormulaFromStructure($formula2);
4801
+ } catch (PHPExcel_Exception $e) {
4802
+ return;
4803
+ }
4804
+ $offset += $sz2;
4805
+
4806
+ // offset: var; size: var; cell range address list with
4807
+ $cellRangeAddressList = $this->_readBIFF8CellRangeAddressList(substr($recordData, $offset));
4808
+ $cellRangeAddresses = $cellRangeAddressList['cellRangeAddresses'];
4809
+
4810
+ foreach ($cellRangeAddresses as $cellRange) {
4811
+ $stRange = $this->_phpSheet->shrinkRangeToFit($cellRange);
4812
+ $stRange = PHPExcel_Cell::extractAllCellReferencesInRange($stRange);
4813
+ foreach ($stRange as $coordinate) {
4814
+ $objValidation = $this->_phpSheet->getCell($coordinate)->getDataValidation();
4815
+ $objValidation->setType($type);
4816
+ $objValidation->setErrorStyle($errorStyle);
4817
+ $objValidation->setAllowBlank((bool)$allowBlank);
4818
+ $objValidation->setShowInputMessage((bool)$showInputMessage);
4819
+ $objValidation->setShowErrorMessage((bool)$showErrorMessage);
4820
+ $objValidation->setShowDropDown(!$suppressDropDown);
4821
+ $objValidation->setOperator($operator);
4822
+ $objValidation->setErrorTitle($errorTitle);
4823
+ $objValidation->setError($error);
4824
+ $objValidation->setPromptTitle($promptTitle);
4825
+ $objValidation->setPrompt($prompt);
4826
+ $objValidation->setFormula1($formula1);
4827
+ $objValidation->setFormula2($formula2);
4828
+ }
4829
+ }
4830
+
4831
+ }
4832
+
4833
+
4834
+ /**
4835
+ * Read SHEETLAYOUT record. Stores sheet tab color information.
4836
+ */
4837
+ private function _readSheetLayout()
4838
+ {
4839
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4840
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4841
+
4842
+ // move stream pointer to next record
4843
+ $this->_pos += 4 + $length;
4844
+
4845
+ // local pointer in record data
4846
+ $offset = 0;
4847
+
4848
+ if (!$this->_readDataOnly) {
4849
+ // offset: 0; size: 2; repeated record identifier 0x0862
4850
+
4851
+ // offset: 2; size: 10; not used
4852
+
4853
+ // offset: 12; size: 4; size of record data
4854
+ // Excel 2003 uses size of 0x14 (documented), Excel 2007 uses size of 0x28 (not documented?)
4855
+ $sz = self::_GetInt4d($recordData, 12);
4856
+
4857
+ switch ($sz) {
4858
+ case 0x14:
4859
+ // offset: 16; size: 2; color index for sheet tab
4860
+ $colorIndex = self::_GetInt2d($recordData, 16);
4861
+ $color = self::_readColor($colorIndex,$this->_palette,$this->_version);
4862
+ $this->_phpSheet->getTabColor()->setRGB($color['rgb']);
4863
+ break;
4864
+
4865
+ case 0x28:
4866
+ // TODO: Investigate structure for .xls SHEETLAYOUT record as saved by MS Office Excel 2007
4867
+ return;
4868
+ break;
4869
+ }
4870
+ }
4871
+ }
4872
+
4873
+
4874
+ /**
4875
+ * Read SHEETPROTECTION record (FEATHEADR)
4876
+ */
4877
+ private function _readSheetProtection()
4878
+ {
4879
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4880
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4881
+
4882
+ // move stream pointer to next record
4883
+ $this->_pos += 4 + $length;
4884
+
4885
+ if ($this->_readDataOnly) {
4886
+ return;
4887
+ }
4888
+
4889
+ // offset: 0; size: 2; repeated record header
4890
+
4891
+ // offset: 2; size: 2; FRT cell reference flag (=0 currently)
4892
+
4893
+ // offset: 4; size: 8; Currently not used and set to 0
4894
+
4895
+ // offset: 12; size: 2; Shared feature type index (2=Enhanced Protetion, 4=SmartTag)
4896
+ $isf = self::_GetInt2d($recordData, 12);
4897
+ if ($isf != 2) {
4898
+ return;
4899
+ }
4900
+
4901
+ // offset: 14; size: 1; =1 since this is a feat header
4902
+
4903
+ // offset: 15; size: 4; size of rgbHdrSData
4904
+
4905
+ // rgbHdrSData, assume "Enhanced Protection"
4906
+ // offset: 19; size: 2; option flags
4907
+ $options = self::_GetInt2d($recordData, 19);
4908
+
4909
+ // bit: 0; mask 0x0001; 1 = user may edit objects, 0 = users must not edit objects
4910
+ $bool = (0x0001 & $options) >> 0;
4911
+ $this->_phpSheet->getProtection()->setObjects(!$bool);
4912
+
4913
+ // bit: 1; mask 0x0002; edit scenarios
4914
+ $bool = (0x0002 & $options) >> 1;
4915
+ $this->_phpSheet->getProtection()->setScenarios(!$bool);
4916
+
4917
+ // bit: 2; mask 0x0004; format cells
4918
+ $bool = (0x0004 & $options) >> 2;
4919
+ $this->_phpSheet->getProtection()->setFormatCells(!$bool);
4920
+
4921
+ // bit: 3; mask 0x0008; format columns
4922
+ $bool = (0x0008 & $options) >> 3;
4923
+ $this->_phpSheet->getProtection()->setFormatColumns(!$bool);
4924
+
4925
+ // bit: 4; mask 0x0010; format rows
4926
+ $bool = (0x0010 & $options) >> 4;
4927
+ $this->_phpSheet->getProtection()->setFormatRows(!$bool);
4928
+
4929
+ // bit: 5; mask 0x0020; insert columns
4930
+ $bool = (0x0020 & $options) >> 5;
4931
+ $this->_phpSheet->getProtection()->setInsertColumns(!$bool);
4932
+
4933
+ // bit: 6; mask 0x0040; insert rows
4934
+ $bool = (0x0040 & $options) >> 6;
4935
+ $this->_phpSheet->getProtection()->setInsertRows(!$bool);
4936
+
4937
+ // bit: 7; mask 0x0080; insert hyperlinks
4938
+ $bool = (0x0080 & $options) >> 7;
4939
+ $this->_phpSheet->getProtection()->setInsertHyperlinks(!$bool);
4940
+
4941
+ // bit: 8; mask 0x0100; delete columns
4942
+ $bool = (0x0100 & $options) >> 8;
4943
+ $this->_phpSheet->getProtection()->setDeleteColumns(!$bool);
4944
+
4945
+ // bit: 9; mask 0x0200; delete rows
4946
+ $bool = (0x0200 & $options) >> 9;
4947
+ $this->_phpSheet->getProtection()->setDeleteRows(!$bool);
4948
+
4949
+ // bit: 10; mask 0x0400; select locked cells
4950
+ $bool = (0x0400 & $options) >> 10;
4951
+ $this->_phpSheet->getProtection()->setSelectLockedCells(!$bool);
4952
+
4953
+ // bit: 11; mask 0x0800; sort cell range
4954
+ $bool = (0x0800 & $options) >> 11;
4955
+ $this->_phpSheet->getProtection()->setSort(!$bool);
4956
+
4957
+ // bit: 12; mask 0x1000; auto filter
4958
+ $bool = (0x1000 & $options) >> 12;
4959
+ $this->_phpSheet->getProtection()->setAutoFilter(!$bool);
4960
+
4961
+ // bit: 13; mask 0x2000; pivot tables
4962
+ $bool = (0x2000 & $options) >> 13;
4963
+ $this->_phpSheet->getProtection()->setPivotTables(!$bool);
4964
+
4965
+ // bit: 14; mask 0x4000; select unlocked cells
4966
+ $bool = (0x4000 & $options) >> 14;
4967
+ $this->_phpSheet->getProtection()->setSelectUnlockedCells(!$bool);
4968
+
4969
+ // offset: 21; size: 2; not used
4970
+ }
4971
+
4972
+
4973
+ /**
4974
+ * Read RANGEPROTECTION record
4975
+ * Reading of this record is based on Microsoft Office Excel 97-2000 Binary File Format Specification,
4976
+ * where it is referred to as FEAT record
4977
+ */
4978
+ private function _readRangeProtection()
4979
+ {
4980
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
4981
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
4982
+
4983
+ // move stream pointer to next record
4984
+ $this->_pos += 4 + $length;
4985
+
4986
+ // local pointer in record data
4987
+ $offset = 0;
4988
+
4989
+ if (!$this->_readDataOnly) {
4990
+ $offset += 12;
4991
+
4992
+ // offset: 12; size: 2; shared feature type, 2 = enhanced protection, 4 = smart tag
4993
+ $isf = self::_GetInt2d($recordData, 12);
4994
+ if ($isf != 2) {
4995
+ // we only read FEAT records of type 2
4996
+ return;
4997
+ }
4998
+ $offset += 2;
4999
+
5000
+ $offset += 5;
5001
+
5002
+ // offset: 19; size: 2; count of ref ranges this feature is on
5003
+ $cref = self::_GetInt2d($recordData, 19);
5004
+ $offset += 2;
5005
+
5006
+ $offset += 6;
5007
+
5008
+ // offset: 27; size: 8 * $cref; list of cell ranges (like in hyperlink record)
5009
+ $cellRanges = array();
5010
+ for ($i = 0; $i < $cref; ++$i) {
5011
+ try {
5012
+ $cellRange = $this->_readBIFF8CellRangeAddressFixed(substr($recordData, 27 + 8 * $i, 8));
5013
+ } catch (PHPExcel_Exception $e) {
5014
+ return;
5015
+ }
5016
+ $cellRanges[] = $cellRange;
5017
+ $offset += 8;
5018
+ }
5019
+
5020
+ // offset: var; size: var; variable length of feature specific data
5021
+ $rgbFeat = substr($recordData, $offset);
5022
+ $offset += 4;
5023
+
5024
+ // offset: var; size: 4; the encrypted password (only 16-bit although field is 32-bit)
5025
+ $wPassword = self::_GetInt4d($recordData, $offset);
5026
+ $offset += 4;
5027
+
5028
+ // Apply range protection to sheet
5029
+ if ($cellRanges) {
5030
+ $this->_phpSheet->protectCells(implode(' ', $cellRanges), strtoupper(dechex($wPassword)), true);
5031
+ }
5032
+ }
5033
+ }
5034
+
5035
+
5036
+ /**
5037
+ * Read IMDATA record
5038
+ */
5039
+ private function _readImData()
5040
+ {
5041
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
5042
+
5043
+ // get spliced record data
5044
+ $splicedRecordData = $this->_getSplicedRecordData();
5045
+ $recordData = $splicedRecordData['recordData'];
5046
+
5047
+ // UNDER CONSTRUCTION
5048
+
5049
+ // offset: 0; size: 2; image format
5050
+ $cf = self::_GetInt2d($recordData, 0);
5051
+
5052
+ // offset: 2; size: 2; environment from which the file was written
5053
+ $env = self::_GetInt2d($recordData, 2);
5054
+
5055
+ // offset: 4; size: 4; length of the image data
5056
+ $lcb = self::_GetInt4d($recordData, 4);
5057
+
5058
+ // offset: 8; size: var; image data
5059
+ $iData = substr($recordData, 8);
5060
+
5061
+ switch ($cf) {
5062
+ case 0x09: // Windows bitmap format
5063
+ // BITMAPCOREINFO
5064
+ // 1. BITMAPCOREHEADER
5065
+ // offset: 0; size: 4; bcSize, Specifies the number of bytes required by the structure
5066
+ $bcSize = self::_GetInt4d($iData, 0);
5067
+ // var_dump($bcSize);
5068
+
5069
+ // offset: 4; size: 2; bcWidth, specifies the width of the bitmap, in pixels
5070
+ $bcWidth = self::_GetInt2d($iData, 4);
5071
+ // var_dump($bcWidth);
5072
+
5073
+ // offset: 6; size: 2; bcHeight, specifies the height of the bitmap, in pixels.
5074
+ $bcHeight = self::_GetInt2d($iData, 6);
5075
+ // var_dump($bcHeight);
5076
+ $ih = imagecreatetruecolor($bcWidth, $bcHeight);
5077
+
5078
+ // offset: 8; size: 2; bcPlanes, specifies the number of planes for the target device. This value must be 1
5079
+
5080
+ // offset: 10; size: 2; bcBitCount specifies the number of bits-per-pixel. This value must be 1, 4, 8, or 24
5081
+ $bcBitCount = self::_GetInt2d($iData, 10);
5082
+ // var_dump($bcBitCount);
5083
+
5084
+ $rgbString = substr($iData, 12);
5085
+ $rgbTriples = array();
5086
+ while (strlen($rgbString) > 0) {
5087
+ $rgbTriples[] = unpack('Cb/Cg/Cr', $rgbString);
5088
+ $rgbString = substr($rgbString, 3);
5089
+ }
5090
+ $x = 0;
5091
+ $y = 0;
5092
+ foreach ($rgbTriples as $i => $rgbTriple) {
5093
+ $color = imagecolorallocate($ih, $rgbTriple['r'], $rgbTriple['g'], $rgbTriple['b']);
5094
+ imagesetpixel($ih, $x, $bcHeight - 1 - $y, $color);
5095
+ $x = ($x + 1) % $bcWidth;
5096
+ $y = $y + floor(($x + 1) / $bcWidth);
5097
+ }
5098
+ //imagepng($ih, 'image.png');
5099
+
5100
+ $drawing = new PHPExcel_Worksheet_Drawing();
5101
+ $drawing->setPath($filename);
5102
+ $drawing->setWorksheet($this->_phpSheet);
5103
+
5104
+ break;
5105
+
5106
+ case 0x02: // Windows metafile or Macintosh PICT format
5107
+ case 0x0e: // native format
5108
+ default;
5109
+ break;
5110
+
5111
+ }
5112
+
5113
+ // _getSplicedRecordData() takes care of moving current position in data stream
5114
+ }
5115
+
5116
+
5117
+ /**
5118
+ * Read a free CONTINUE record. Free CONTINUE record may be a camouflaged MSODRAWING record
5119
+ * When MSODRAWING data on a sheet exceeds 8224 bytes, CONTINUE records are used instead. Undocumented.
5120
+ * In this case, we must treat the CONTINUE record as a MSODRAWING record
5121
+ */
5122
+ private function _readContinue()
5123
+ {
5124
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
5125
+ $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
5126
+
5127
+ // check if we are reading drawing data
5128
+ // this is in case a free CONTINUE record occurs in other circumstances we are unaware of
5129
+ if ($this->_drawingData == '') {
5130
+ // move stream pointer to next record
5131
+ $this->_pos += 4 + $length;
5132
+
5133
+ return;
5134
+ }
5135
+
5136
+ // check if record data is at least 4 bytes long, otherwise there is no chance this is MSODRAWING data
5137
+ if ($length < 4) {
5138
+ // move stream pointer to next record
5139
+ $this->_pos += 4 + $length;
5140
+
5141
+ return;
5142
+ }
5143
+
5144
+ // dirty check to see if CONTINUE record could be a camouflaged MSODRAWING record
5145
+ // look inside CONTINUE record to see if it looks like a part of an Escher stream
5146
+ // we know that Escher stream may be split at least at
5147
+ // 0xF003 MsofbtSpgrContainer
5148
+ // 0xF004 MsofbtSpContainer
5149
+ // 0xF00D MsofbtClientTextbox
5150
+ $validSplitPoints = array(0xF003, 0xF004, 0xF00D); // add identifiers if we find more
5151
+
5152
+ $splitPoint = self::_GetInt2d($recordData, 2);
5153
+ if (in_array($splitPoint, $validSplitPoints)) {
5154
+ // get spliced record data (and move pointer to next record)
5155
+ $splicedRecordData = $this->_getSplicedRecordData();
5156
+ $this->_drawingData .= $splicedRecordData['recordData'];
5157
+
5158
+ return;
5159
+ }
5160
+
5161
+ // move stream pointer to next record
5162
+ $this->_pos += 4 + $length;
5163
+
5164
+ }
5165
+
5166
+
5167
+ /**
5168
+ * Reads a record from current position in data stream and continues reading data as long as CONTINUE
5169
+ * records are found. Splices the record data pieces and returns the combined string as if record data
5170
+ * is in one piece.
5171
+ * Moves to next current position in data stream to start of next record different from a CONtINUE record
5172
+ *
5173
+ * @return array
5174
+ */
5175
+ private function _getSplicedRecordData()
5176
+ {
5177
+ $data = '';
5178
+ $spliceOffsets = array();
5179
+
5180
+ $i = 0;
5181
+ $spliceOffsets[0] = 0;
5182
+
5183
+ do {
5184
+ ++$i;
5185
+
5186
+ // offset: 0; size: 2; identifier
5187
+ $identifier = self::_GetInt2d($this->_data, $this->_pos);
5188
+ // offset: 2; size: 2; length
5189
+ $length = self::_GetInt2d($this->_data, $this->_pos + 2);
5190
+ $data .= $this->_readRecordData($this->_data, $this->_pos + 4, $length);
5191
+
5192
+ $spliceOffsets[$i] = $spliceOffsets[$i - 1] + $length;
5193
+
5194
+ $this->_pos += 4 + $length;
5195
+ $nextIdentifier = self::_GetInt2d($this->_data, $this->_pos);
5196
+ }
5197
+ while ($nextIdentifier == self::XLS_Type_CONTINUE);
5198
+
5199
+ $splicedData = array(
5200
+ 'recordData' => $data,
5201
+ 'spliceOffsets' => $spliceOffsets,
5202
+ );
5203
+
5204
+ return $splicedData;
5205
+
5206
+ }
5207
+
5208
+
5209
+ /**
5210
+ * Convert formula structure into human readable Excel formula like 'A3+A5*5'
5211
+ *
5212
+ * @param string $formulaStructure The complete binary data for the formula
5213
+ * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5214
+ * @return string Human readable formula
5215
+ */
5216
+ private function _getFormulaFromStructure($formulaStructure, $baseCell = 'A1')
5217
+ {
5218
+ // offset: 0; size: 2; size of the following formula data
5219
+ $sz = self::_GetInt2d($formulaStructure, 0);
5220
+
5221
+ // offset: 2; size: sz
5222
+ $formulaData = substr($formulaStructure, 2, $sz);
5223
+
5224
+ // for debug: dump the formula data
5225
+ //echo '<xmp>';
5226
+ //echo 'size: ' . $sz . "\n";
5227
+ //echo 'the entire formula data: ';
5228
+ //Debug::dump($formulaData);
5229
+ //echo "\n----\n";
5230
+
5231
+ // offset: 2 + sz; size: variable (optional)
5232
+ if (strlen($formulaStructure) > 2 + $sz) {
5233
+ $additionalData = substr($formulaStructure, 2 + $sz);
5234
+
5235
+ // for debug: dump the additional data
5236
+ //echo 'the entire additional data: ';
5237
+ //Debug::dump($additionalData);
5238
+ //echo "\n----\n";
5239
+
5240
+ } else {
5241
+ $additionalData = '';
5242
+ }
5243
+
5244
+ return $this->_getFormulaFromData($formulaData, $additionalData, $baseCell);
5245
+ }
5246
+
5247
+
5248
+ /**
5249
+ * Take formula data and additional data for formula and return human readable formula
5250
+ *
5251
+ * @param string $formulaData The binary data for the formula itself
5252
+ * @param string $additionalData Additional binary data going with the formula
5253
+ * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5254
+ * @return string Human readable formula
5255
+ */
5256
+ private function _getFormulaFromData($formulaData, $additionalData = '', $baseCell = 'A1')
5257
+ {
5258
+ // start parsing the formula data
5259
+ $tokens = array();
5260
+
5261
+ while (strlen($formulaData) > 0 and $token = $this->_getNextToken($formulaData, $baseCell)) {
5262
+ $tokens[] = $token;
5263
+ $formulaData = substr($formulaData, $token['size']);
5264
+
5265
+ // for debug: dump the token
5266
+ //var_dump($token);
5267
+ }
5268
+
5269
+ $formulaString = $this->_createFormulaFromTokens($tokens, $additionalData);
5270
+
5271
+ return $formulaString;
5272
+ }
5273
+
5274
+
5275
+ /**
5276
+ * Take array of tokens together with additional data for formula and return human readable formula
5277
+ *
5278
+ * @param array $tokens
5279
+ * @param array $additionalData Additional binary data going with the formula
5280
+ * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5281
+ * @return string Human readable formula
5282
+ */
5283
+ private function _createFormulaFromTokens($tokens, $additionalData)
5284
+ {
5285
+ // empty formula?
5286
+ if (empty($tokens)) {
5287
+ return '';
5288
+ }
5289
+
5290
+ $formulaStrings = array();
5291
+ foreach ($tokens as $token) {
5292
+ // initialize spaces
5293
+ $space0 = isset($space0) ? $space0 : ''; // spaces before next token, not tParen
5294
+ $space1 = isset($space1) ? $space1 : ''; // carriage returns before next token, not tParen
5295
+ $space2 = isset($space2) ? $space2 : ''; // spaces before opening parenthesis
5296
+ $space3 = isset($space3) ? $space3 : ''; // carriage returns before opening parenthesis
5297
+ $space4 = isset($space4) ? $space4 : ''; // spaces before closing parenthesis
5298
+ $space5 = isset($space5) ? $space5 : ''; // carriage returns before closing parenthesis
5299
+
5300
+ switch ($token['name']) {
5301
+ case 'tAdd': // addition
5302
+ case 'tConcat': // addition
5303
+ case 'tDiv': // division
5304
+ case 'tEQ': // equality
5305
+ case 'tGE': // greater than or equal
5306
+ case 'tGT': // greater than
5307
+ case 'tIsect': // intersection
5308
+ case 'tLE': // less than or equal
5309
+ case 'tList': // less than or equal
5310
+ case 'tLT': // less than
5311
+ case 'tMul': // multiplication
5312
+ case 'tNE': // multiplication
5313
+ case 'tPower': // power
5314
+ case 'tRange': // range
5315
+ case 'tSub': // subtraction
5316
+ $op2 = array_pop($formulaStrings);
5317
+ $op1 = array_pop($formulaStrings);
5318
+ $formulaStrings[] = "$op1$space1$space0{$token['data']}$op2";
5319
+ unset($space0, $space1);
5320
+ break;
5321
+ case 'tUplus': // unary plus
5322
+ case 'tUminus': // unary minus
5323
+ $op = array_pop($formulaStrings);
5324
+ $formulaStrings[] = "$space1$space0{$token['data']}$op";
5325
+ unset($space0, $space1);
5326
+ break;
5327
+ case 'tPercent': // percent sign
5328
+ $op = array_pop($formulaStrings);
5329
+ $formulaStrings[] = "$op$space1$space0{$token['data']}";
5330
+ unset($space0, $space1);
5331
+ break;
5332
+ case 'tAttrVolatile': // indicates volatile function
5333
+ case 'tAttrIf':
5334
+ case 'tAttrSkip':
5335
+ case 'tAttrChoose':
5336
+ // token is only important for Excel formula evaluator
5337
+ // do nothing
5338
+ break;
5339
+ case 'tAttrSpace': // space / carriage return
5340
+ // space will be used when next token arrives, do not alter formulaString stack
5341
+ switch ($token['data']['spacetype']) {
5342
+ case 'type0':
5343
+ $space0 = str_repeat(' ', $token['data']['spacecount']);
5344
+ break;
5345
+ case 'type1':
5346
+ $space1 = str_repeat("\n", $token['data']['spacecount']);
5347
+ break;
5348
+ case 'type2':
5349
+ $space2 = str_repeat(' ', $token['data']['spacecount']);
5350
+ break;
5351
+ case 'type3':
5352
+ $space3 = str_repeat("\n", $token['data']['spacecount']);
5353
+ break;
5354
+ case 'type4':
5355
+ $space4 = str_repeat(' ', $token['data']['spacecount']);
5356
+ break;
5357
+ case 'type5':
5358
+ $space5 = str_repeat("\n", $token['data']['spacecount']);
5359
+ break;
5360
+ }
5361
+ break;
5362
+ case 'tAttrSum': // SUM function with one parameter
5363
+ $op = array_pop($formulaStrings);
5364
+ $formulaStrings[] = "{$space1}{$space0}SUM($op)";
5365
+ unset($space0, $space1);
5366
+ break;
5367
+ case 'tFunc': // function with fixed number of arguments
5368
+ case 'tFuncV': // function with variable number of arguments
5369
+ if ($token['data']['function'] != '') {
5370
+ // normal function
5371
+ $ops = array(); // array of operators
5372
+ for ($i = 0; $i < $token['data']['args']; ++$i) {
5373
+ $ops[] = array_pop($formulaStrings);
5374
+ }
5375
+ $ops = array_reverse($ops);
5376
+ $formulaStrings[] = "$space1$space0{$token['data']['function']}(" . implode(',', $ops) . ")";
5377
+ unset($space0, $space1);
5378
+ } else {
5379
+ // add-in function
5380
+ $ops = array(); // array of operators
5381
+ for ($i = 0; $i < $token['data']['args'] - 1; ++$i) {
5382
+ $ops[] = array_pop($formulaStrings);
5383
+ }
5384
+ $ops = array_reverse($ops);
5385
+ $function = array_pop($formulaStrings);
5386
+ $formulaStrings[] = "$space1$space0$function(" . implode(',', $ops) . ")";
5387
+ unset($space0, $space1);
5388
+ }
5389
+ break;
5390
+ case 'tParen': // parenthesis
5391
+ $expression = array_pop($formulaStrings);
5392
+ $formulaStrings[] = "$space3$space2($expression$space5$space4)";
5393
+ unset($space2, $space3, $space4, $space5);
5394
+ break;
5395
+ case 'tArray': // array constant
5396
+ $constantArray = self::_readBIFF8ConstantArray($additionalData);
5397
+ $formulaStrings[] = $space1 . $space0 . $constantArray['value'];
5398
+ $additionalData = substr($additionalData, $constantArray['size']); // bite of chunk of additional data
5399
+ unset($space0, $space1);
5400
+ break;
5401
+ case 'tMemArea':
5402
+ // bite off chunk of additional data
5403
+ $cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($additionalData);
5404
+ $additionalData = substr($additionalData, $cellRangeAddressList['size']);
5405
+ $formulaStrings[] = "$space1$space0{$token['data']}";
5406
+ unset($space0, $space1);
5407
+ break;
5408
+ case 'tArea': // cell range address
5409
+ case 'tBool': // boolean
5410
+ case 'tErr': // error code
5411
+ case 'tInt': // integer
5412
+ case 'tMemErr':
5413
+ case 'tMemFunc':
5414
+ case 'tMissArg':
5415
+ case 'tName':
5416
+ case 'tNameX':
5417
+ case 'tNum': // number
5418
+ case 'tRef': // single cell reference
5419
+ case 'tRef3d': // 3d cell reference
5420
+ case 'tArea3d': // 3d cell range reference
5421
+ case 'tRefN':
5422
+ case 'tAreaN':
5423
+ case 'tStr': // string
5424
+ $formulaStrings[] = "$space1$space0{$token['data']}";
5425
+ unset($space0, $space1);
5426
+ break;
5427
+ }
5428
+ }
5429
+ $formulaString = $formulaStrings[0];
5430
+
5431
+ // for debug: dump the human readable formula
5432
+ //echo '----' . "\n";
5433
+ //echo 'Formula: ' . $formulaString;
5434
+
5435
+ return $formulaString;
5436
+ }
5437
+
5438
+
5439
+ /**
5440
+ * Fetch next token from binary formula data
5441
+ *
5442
+ * @param string Formula data
5443
+ * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5444
+ * @return array
5445
+ * @throws PHPExcel_Reader_Exception
5446
+ */
5447
+ private function _getNextToken($formulaData, $baseCell = 'A1')
5448
+ {
5449
+ // offset: 0; size: 1; token id
5450
+ $id = ord($formulaData[0]); // token id
5451
+ $name = false; // initialize token name
5452
+
5453
+ switch ($id) {
5454
+ case 0x03: $name = 'tAdd'; $size = 1; $data = '+'; break;
5455
+ case 0x04: $name = 'tSub'; $size = 1; $data = '-'; break;
5456
+ case 0x05: $name = 'tMul'; $size = 1; $data = '*'; break;
5457
+ case 0x06: $name = 'tDiv'; $size = 1; $data = '/'; break;
5458
+ case 0x07: $name = 'tPower'; $size = 1; $data = '^'; break;
5459
+ case 0x08: $name = 'tConcat'; $size = 1; $data = '&'; break;
5460
+ case 0x09: $name = 'tLT'; $size = 1; $data = '<'; break;
5461
+ case 0x0A: $name = 'tLE'; $size = 1; $data = '<='; break;
5462
+ case 0x0B: $name = 'tEQ'; $size = 1; $data = '='; break;
5463
+ case 0x0C: $name = 'tGE'; $size = 1; $data = '>='; break;
5464
+ case 0x0D: $name = 'tGT'; $size = 1; $data = '>'; break;
5465
+ case 0x0E: $name = 'tNE'; $size = 1; $data = '<>'; break;
5466
+ case 0x0F: $name = 'tIsect'; $size = 1; $data = ' '; break;
5467
+ case 0x10: $name = 'tList'; $size = 1; $data = ','; break;
5468
+ case 0x11: $name = 'tRange'; $size = 1; $data = ':'; break;
5469
+ case 0x12: $name = 'tUplus'; $size = 1; $data = '+'; break;
5470
+ case 0x13: $name = 'tUminus'; $size = 1; $data = '-'; break;
5471
+ case 0x14: $name = 'tPercent'; $size = 1; $data = '%'; break;
5472
+ case 0x15: // parenthesis
5473
+ $name = 'tParen';
5474
+ $size = 1;
5475
+ $data = null;
5476
+ break;
5477
+ case 0x16: // missing argument
5478
+ $name = 'tMissArg';
5479
+ $size = 1;
5480
+ $data = '';
5481
+ break;
5482
+ case 0x17: // string
5483
+ $name = 'tStr';
5484
+ // offset: 1; size: var; Unicode string, 8-bit string length
5485
+ $string = self::_readUnicodeStringShort(substr($formulaData, 1));
5486
+ $size = 1 + $string['size'];
5487
+ $data = self::_UTF8toExcelDoubleQuoted($string['value']);
5488
+ break;
5489
+ case 0x19: // Special attribute
5490
+ // offset: 1; size: 1; attribute type flags:
5491
+ switch (ord($formulaData[1])) {
5492
+ case 0x01:
5493
+ $name = 'tAttrVolatile';
5494
+ $size = 4;
5495
+ $data = null;
5496
+ break;
5497
+ case 0x02:
5498
+ $name = 'tAttrIf';
5499
+ $size = 4;
5500
+ $data = null;
5501
+ break;
5502
+ case 0x04:
5503
+ $name = 'tAttrChoose';
5504
+ // offset: 2; size: 2; number of choices in the CHOOSE function ($nc, number of parameters decreased by 1)
5505
+ $nc = self::_GetInt2d($formulaData, 2);
5506
+ // offset: 4; size: 2 * $nc
5507
+ // offset: 4 + 2 * $nc; size: 2
5508
+ $size = 2 * $nc + 6;
5509
+ $data = null;
5510
+ break;
5511
+ case 0x08:
5512
+ $name = 'tAttrSkip';
5513
+ $size = 4;
5514
+ $data = null;
5515
+ break;
5516
+ case 0x10:
5517
+ $name = 'tAttrSum';
5518
+ $size = 4;
5519
+ $data = null;
5520
+ break;
5521
+ case 0x40:
5522
+ case 0x41:
5523
+ $name = 'tAttrSpace';
5524
+ $size = 4;
5525
+ // offset: 2; size: 2; space type and position
5526
+ switch (ord($formulaData[2])) {
5527
+ case 0x00:
5528
+ $spacetype = 'type0';
5529
+ break;
5530
+ case 0x01:
5531
+ $spacetype = 'type1';
5532
+ break;
5533
+ case 0x02:
5534
+ $spacetype = 'type2';
5535
+ break;
5536
+ case 0x03:
5537
+ $spacetype = 'type3';
5538
+ break;
5539
+ case 0x04:
5540
+ $spacetype = 'type4';
5541
+ break;
5542
+ case 0x05:
5543
+ $spacetype = 'type5';
5544
+ break;
5545
+ default:
5546
+ throw new PHPExcel_Reader_Exception('Unrecognized space type in tAttrSpace token');
5547
+ break;
5548
+ }
5549
+ // offset: 3; size: 1; number of inserted spaces/carriage returns
5550
+ $spacecount = ord($formulaData[3]);
5551
+
5552
+ $data = array('spacetype' => $spacetype, 'spacecount' => $spacecount);
5553
+ break;
5554
+ default:
5555
+ throw new PHPExcel_Reader_Exception('Unrecognized attribute flag in tAttr token');
5556
+ break;
5557
+ }
5558
+ break;
5559
+ case 0x1C: // error code
5560
+ // offset: 1; size: 1; error code
5561
+ $name = 'tErr';
5562
+ $size = 2;
5563
+ $data = self::_mapErrorCode(ord($formulaData[1]));
5564
+ break;
5565
+ case 0x1D: // boolean
5566
+ // offset: 1; size: 1; 0 = false, 1 = true;
5567
+ $name = 'tBool';
5568
+ $size = 2;
5569
+ $data = ord($formulaData[1]) ? 'TRUE' : 'FALSE';
5570
+ break;
5571
+ case 0x1E: // integer
5572
+ // offset: 1; size: 2; unsigned 16-bit integer
5573
+ $name = 'tInt';
5574
+ $size = 3;
5575
+ $data = self::_GetInt2d($formulaData, 1);
5576
+ break;
5577
+ case 0x1F: // number
5578
+ // offset: 1; size: 8;
5579
+ $name = 'tNum';
5580
+ $size = 9;
5581
+ $data = self::_extractNumber(substr($formulaData, 1));
5582
+ $data = str_replace(',', '.', (string)$data); // in case non-English locale
5583
+ break;
5584
+ case 0x20: // array constant
5585
+ case 0x40:
5586
+ case 0x60:
5587
+ // offset: 1; size: 7; not used
5588
+ $name = 'tArray';
5589
+ $size = 8;
5590
+ $data = null;
5591
+ break;
5592
+ case 0x21: // function with fixed number of arguments
5593
+ case 0x41:
5594
+ case 0x61:
5595
+ $name = 'tFunc';
5596
+ $size = 3;
5597
+ // offset: 1; size: 2; index to built-in sheet function
5598
+ switch (self::_GetInt2d($formulaData, 1)) {
5599
+ case 2: $function = 'ISNA'; $args = 1; break;
5600
+ case 3: $function = 'ISERROR'; $args = 1; break;
5601
+ case 10: $function = 'NA'; $args = 0; break;
5602
+ case 15: $function = 'SIN'; $args = 1; break;
5603
+ case 16: $function = 'COS'; $args = 1; break;
5604
+ case 17: $function = 'TAN'; $args = 1; break;
5605
+ case 18: $function = 'ATAN'; $args = 1; break;
5606
+ case 19: $function = 'PI'; $args = 0; break;
5607
+ case 20: $function = 'SQRT'; $args = 1; break;
5608
+ case 21: $function = 'EXP'; $args = 1; break;
5609
+ case 22: $function = 'LN'; $args = 1; break;
5610
+ case 23: $function = 'LOG10'; $args = 1; break;
5611
+ case 24: $function = 'ABS'; $args = 1; break;
5612
+ case 25: $function = 'INT'; $args = 1; break;
5613
+ case 26: $function = 'SIGN'; $args = 1; break;
5614
+ case 27: $function = 'ROUND'; $args = 2; break;
5615
+ case 30: $function = 'REPT'; $args = 2; break;
5616
+ case 31: $function = 'MID'; $args = 3; break;
5617
+ case 32: $function = 'LEN'; $args = 1; break;
5618
+ case 33: $function = 'VALUE'; $args = 1; break;
5619
+ case 34: $function = 'TRUE'; $args = 0; break;
5620
+ case 35: $function = 'FALSE'; $args = 0; break;
5621
+ case 38: $function = 'NOT'; $args = 1; break;
5622
+ case 39: $function = 'MOD'; $args = 2; break;
5623
+ case 40: $function = 'DCOUNT'; $args = 3; break;
5624
+ case 41: $function = 'DSUM'; $args = 3; break;
5625
+ case 42: $function = 'DAVERAGE'; $args = 3; break;
5626
+ case 43: $function = 'DMIN'; $args = 3; break;
5627
+ case 44: $function = 'DMAX'; $args = 3; break;
5628
+ case 45: $function = 'DSTDEV'; $args = 3; break;
5629
+ case 48: $function = 'TEXT'; $args = 2; break;
5630
+ case 61: $function = 'MIRR'; $args = 3; break;
5631
+ case 63: $function = 'RAND'; $args = 0; break;
5632
+ case 65: $function = 'DATE'; $args = 3; break;
5633
+ case 66: $function = 'TIME'; $args = 3; break;
5634
+ case 67: $function = 'DAY'; $args = 1; break;
5635
+ case 68: $function = 'MONTH'; $args = 1; break;
5636
+ case 69: $function = 'YEAR'; $args = 1; break;
5637
+ case 71: $function = 'HOUR'; $args = 1; break;
5638
+ case 72: $function = 'MINUTE'; $args = 1; break;
5639
+ case 73: $function = 'SECOND'; $args = 1; break;
5640
+ case 74: $function = 'NOW'; $args = 0; break;
5641
+ case 75: $function = 'AREAS'; $args = 1; break;
5642
+ case 76: $function = 'ROWS'; $args = 1; break;
5643
+ case 77: $function = 'COLUMNS'; $args = 1; break;
5644
+ case 83: $function = 'TRANSPOSE'; $args = 1; break;
5645
+ case 86: $function = 'TYPE'; $args = 1; break;
5646
+ case 97: $function = 'ATAN2'; $args = 2; break;
5647
+ case 98: $function = 'ASIN'; $args = 1; break;
5648
+ case 99: $function = 'ACOS'; $args = 1; break;
5649
+ case 105: $function = 'ISREF'; $args = 1; break;
5650
+ case 111: $function = 'CHAR'; $args = 1; break;
5651
+ case 112: $function = 'LOWER'; $args = 1; break;
5652
+ case 113: $function = 'UPPER'; $args = 1; break;
5653
+ case 114: $function = 'PROPER'; $args = 1; break;
5654
+ case 117: $function = 'EXACT'; $args = 2; break;
5655
+ case 118: $function = 'TRIM'; $args = 1; break;
5656
+ case 119: $function = 'REPLACE'; $args = 4; break;
5657
+ case 121: $function = 'CODE'; $args = 1; break;
5658
+ case 126: $function = 'ISERR'; $args = 1; break;
5659
+ case 127: $function = 'ISTEXT'; $args = 1; break;
5660
+ case 128: $function = 'ISNUMBER'; $args = 1; break;
5661
+ case 129: $function = 'ISBLANK'; $args = 1; break;
5662
+ case 130: $function = 'T'; $args = 1; break;
5663
+ case 131: $function = 'N'; $args = 1; break;
5664
+ case 140: $function = 'DATEVALUE'; $args = 1; break;
5665
+ case 141: $function = 'TIMEVALUE'; $args = 1; break;
5666
+ case 142: $function = 'SLN'; $args = 3; break;
5667
+ case 143: $function = 'SYD'; $args = 4; break;
5668
+ case 162: $function = 'CLEAN'; $args = 1; break;
5669
+ case 163: $function = 'MDETERM'; $args = 1; break;
5670
+ case 164: $function = 'MINVERSE'; $args = 1; break;
5671
+ case 165: $function = 'MMULT'; $args = 2; break;
5672
+ case 184: $function = 'FACT'; $args = 1; break;
5673
+ case 189: $function = 'DPRODUCT'; $args = 3; break;
5674
+ case 190: $function = 'ISNONTEXT'; $args = 1; break;
5675
+ case 195: $function = 'DSTDEVP'; $args = 3; break;
5676
+ case 196: $function = 'DVARP'; $args = 3; break;
5677
+ case 198: $function = 'ISLOGICAL'; $args = 1; break;
5678
+ case 199: $function = 'DCOUNTA'; $args = 3; break;
5679
+ case 207: $function = 'REPLACEB'; $args = 4; break;
5680
+ case 210: $function = 'MIDB'; $args = 3; break;
5681
+ case 211: $function = 'LENB'; $args = 1; break;
5682
+ case 212: $function = 'ROUNDUP'; $args = 2; break;
5683
+ case 213: $function = 'ROUNDDOWN'; $args = 2; break;
5684
+ case 214: $function = 'ASC'; $args = 1; break;
5685
+ case 215: $function = 'DBCS'; $args = 1; break;
5686
+ case 221: $function = 'TODAY'; $args = 0; break;
5687
+ case 229: $function = 'SINH'; $args = 1; break;
5688
+ case 230: $function = 'COSH'; $args = 1; break;
5689
+ case 231: $function = 'TANH'; $args = 1; break;
5690
+ case 232: $function = 'ASINH'; $args = 1; break;
5691
+ case 233: $function = 'ACOSH'; $args = 1; break;
5692
+ case 234: $function = 'ATANH'; $args = 1; break;
5693
+ case 235: $function = 'DGET'; $args = 3; break;
5694
+ case 244: $function = 'INFO'; $args = 1; break;
5695
+ case 252: $function = 'FREQUENCY'; $args = 2; break;
5696
+ case 261: $function = 'ERROR.TYPE'; $args = 1; break;
5697
+ case 271: $function = 'GAMMALN'; $args = 1; break;
5698
+ case 273: $function = 'BINOMDIST'; $args = 4; break;
5699
+ case 274: $function = 'CHIDIST'; $args = 2; break;
5700
+ case 275: $function = 'CHIINV'; $args = 2; break;
5701
+ case 276: $function = 'COMBIN'; $args = 2; break;
5702
+ case 277: $function = 'CONFIDENCE'; $args = 3; break;
5703
+ case 278: $function = 'CRITBINOM'; $args = 3; break;
5704
+ case 279: $function = 'EVEN'; $args = 1; break;
5705
+ case 280: $function = 'EXPONDIST'; $args = 3; break;
5706
+ case 281: $function = 'FDIST'; $args = 3; break;
5707
+ case 282: $function = 'FINV'; $args = 3; break;
5708
+ case 283: $function = 'FISHER'; $args = 1; break;
5709
+ case 284: $function = 'FISHERINV'; $args = 1; break;
5710
+ case 285: $function = 'FLOOR'; $args = 2; break;
5711
+ case 286: $function = 'GAMMADIST'; $args = 4; break;
5712
+ case 287: $function = 'GAMMAINV'; $args = 3; break;
5713
+ case 288: $function = 'CEILING'; $args = 2; break;
5714
+ case 289: $function = 'HYPGEOMDIST'; $args = 4; break;
5715
+ case 290: $function = 'LOGNORMDIST'; $args = 3; break;
5716
+ case 291: $function = 'LOGINV'; $args = 3; break;
5717
+ case 292: $function = 'NEGBINOMDIST'; $args = 3; break;
5718
+ case 293: $function = 'NORMDIST'; $args = 4; break;
5719
+ case 294: $function = 'NORMSDIST'; $args = 1; break;
5720
+ case 295: $function = 'NORMINV'; $args = 3; break;
5721
+ case 296: $function = 'NORMSINV'; $args = 1; break;
5722
+ case 297: $function = 'STANDARDIZE'; $args = 3; break;
5723
+ case 298: $function = 'ODD'; $args = 1; break;
5724
+ case 299: $function = 'PERMUT'; $args = 2; break;
5725
+ case 300: $function = 'POISSON'; $args = 3; break;
5726
+ case 301: $function = 'TDIST'; $args = 3; break;
5727
+ case 302: $function = 'WEIBULL'; $args = 4; break;
5728
+ case 303: $function = 'SUMXMY2'; $args = 2; break;
5729
+ case 304: $function = 'SUMX2MY2'; $args = 2; break;
5730
+ case 305: $function = 'SUMX2PY2'; $args = 2; break;
5731
+ case 306: $function = 'CHITEST'; $args = 2; break;
5732
+ case 307: $function = 'CORREL'; $args = 2; break;
5733
+ case 308: $function = 'COVAR'; $args = 2; break;
5734
+ case 309: $function = 'FORECAST'; $args = 3; break;
5735
+ case 310: $function = 'FTEST'; $args = 2; break;
5736
+ case 311: $function = 'INTERCEPT'; $args = 2; break;
5737
+ case 312: $function = 'PEARSON'; $args = 2; break;
5738
+ case 313: $function = 'RSQ'; $args = 2; break;
5739
+ case 314: $function = 'STEYX'; $args = 2; break;
5740
+ case 315: $function = 'SLOPE'; $args = 2; break;
5741
+ case 316: $function = 'TTEST'; $args = 4; break;
5742
+ case 325: $function = 'LARGE'; $args = 2; break;
5743
+ case 326: $function = 'SMALL'; $args = 2; break;
5744
+ case 327: $function = 'QUARTILE'; $args = 2; break;
5745
+ case 328: $function = 'PERCENTILE'; $args = 2; break;
5746
+ case 331: $function = 'TRIMMEAN'; $args = 2; break;
5747
+ case 332: $function = 'TINV'; $args = 2; break;
5748
+ case 337: $function = 'POWER'; $args = 2; break;
5749
+ case 342: $function = 'RADIANS'; $args = 1; break;
5750
+ case 343: $function = 'DEGREES'; $args = 1; break;
5751
+ case 346: $function = 'COUNTIF'; $args = 2; break;
5752
+ case 347: $function = 'COUNTBLANK'; $args = 1; break;
5753
+ case 350: $function = 'ISPMT'; $args = 4; break;
5754
+ case 351: $function = 'DATEDIF'; $args = 3; break;
5755
+ case 352: $function = 'DATESTRING'; $args = 1; break;
5756
+ case 353: $function = 'NUMBERSTRING'; $args = 2; break;
5757
+ case 360: $function = 'PHONETIC'; $args = 1; break;
5758
+ case 368: $function = 'BAHTTEXT'; $args = 1; break;
5759
+ default:
5760
+ throw new PHPExcel_Reader_Exception('Unrecognized function in formula');
5761
+ break;
5762
+ }
5763
+ $data = array('function' => $function, 'args' => $args);
5764
+ break;
5765
+ case 0x22: // function with variable number of arguments
5766
+ case 0x42:
5767
+ case 0x62:
5768
+ $name = 'tFuncV';
5769
+ $size = 4;
5770
+ // offset: 1; size: 1; number of arguments
5771
+ $args = ord($formulaData[1]);
5772
+ // offset: 2: size: 2; index to built-in sheet function
5773
+ $index = self::_GetInt2d($formulaData, 2);
5774
+ switch ($index) {
5775
+ case 0: $function = 'COUNT'; break;
5776
+ case 1: $function = 'IF'; break;
5777
+ case 4: $function = 'SUM'; break;
5778
+ case 5: $function = 'AVERAGE'; break;
5779
+ case 6: $function = 'MIN'; break;
5780
+ case 7: $function = 'MAX'; break;
5781
+ case 8: $function = 'ROW'; break;
5782
+ case 9: $function = 'COLUMN'; break;
5783
+ case 11: $function = 'NPV'; break;
5784
+ case 12: $function = 'STDEV'; break;
5785
+ case 13: $function = 'DOLLAR'; break;
5786
+ case 14: $function = 'FIXED'; break;
5787
+ case 28: $function = 'LOOKUP'; break;
5788
+ case 29: $function = 'INDEX'; break;
5789
+ case 36: $function = 'AND'; break;
5790
+ case 37: $function = 'OR'; break;
5791
+ case 46: $function = 'VAR'; break;
5792
+ case 49: $function = 'LINEST'; break;
5793
+ case 50: $function = 'TREND'; break;
5794
+ case 51: $function = 'LOGEST'; break;
5795
+ case 52: $function = 'GROWTH'; break;
5796
+ case 56: $function = 'PV'; break;
5797
+ case 57: $function = 'FV'; break;
5798
+ case 58: $function = 'NPER'; break;
5799
+ case 59: $function = 'PMT'; break;
5800
+ case 60: $function = 'RATE'; break;
5801
+ case 62: $function = 'IRR'; break;
5802
+ case 64: $function = 'MATCH'; break;
5803
+ case 70: $function = 'WEEKDAY'; break;
5804
+ case 78: $function = 'OFFSET'; break;
5805
+ case 82: $function = 'SEARCH'; break;
5806
+ case 100: $function = 'CHOOSE'; break;
5807
+ case 101: $function = 'HLOOKUP'; break;
5808
+ case 102: $function = 'VLOOKUP'; break;
5809
+ case 109: $function = 'LOG'; break;
5810
+ case 115: $function = 'LEFT'; break;
5811
+ case 116: $function = 'RIGHT'; break;
5812
+ case 120: $function = 'SUBSTITUTE'; break;
5813
+ case 124: $function = 'FIND'; break;
5814
+ case 125: $function = 'CELL'; break;
5815
+ case 144: $function = 'DDB'; break;
5816
+ case 148: $function = 'INDIRECT'; break;
5817
+ case 167: $function = 'IPMT'; break;
5818
+ case 168: $function = 'PPMT'; break;
5819
+ case 169: $function = 'COUNTA'; break;
5820
+ case 183: $function = 'PRODUCT'; break;
5821
+ case 193: $function = 'STDEVP'; break;
5822
+ case 194: $function = 'VARP'; break;
5823
+ case 197: $function = 'TRUNC'; break;
5824
+ case 204: $function = 'USDOLLAR'; break;
5825
+ case 205: $function = 'FINDB'; break;
5826
+ case 206: $function = 'SEARCHB'; break;
5827
+ case 208: $function = 'LEFTB'; break;
5828
+ case 209: $function = 'RIGHTB'; break;
5829
+ case 216: $function = 'RANK'; break;
5830
+ case 219: $function = 'ADDRESS'; break;
5831
+ case 220: $function = 'DAYS360'; break;
5832
+ case 222: $function = 'VDB'; break;
5833
+ case 227: $function = 'MEDIAN'; break;
5834
+ case 228: $function = 'SUMPRODUCT'; break;
5835
+ case 247: $function = 'DB'; break;
5836
+ case 255: $function = ''; break;
5837
+ case 269: $function = 'AVEDEV'; break;
5838
+ case 270: $function = 'BETADIST'; break;
5839
+ case 272: $function = 'BETAINV'; break;
5840
+ case 317: $function = 'PROB'; break;
5841
+ case 318: $function = 'DEVSQ'; break;
5842
+ case 319: $function = 'GEOMEAN'; break;
5843
+ case 320: $function = 'HARMEAN'; break;
5844
+ case 321: $function = 'SUMSQ'; break;
5845
+ case 322: $function = 'KURT'; break;
5846
+ case 323: $function = 'SKEW'; break;
5847
+ case 324: $function = 'ZTEST'; break;
5848
+ case 329: $function = 'PERCENTRANK'; break;
5849
+ case 330: $function = 'MODE'; break;
5850
+ case 336: $function = 'CONCATENATE'; break;
5851
+ case 344: $function = 'SUBTOTAL'; break;
5852
+ case 345: $function = 'SUMIF'; break;
5853
+ case 354: $function = 'ROMAN'; break;
5854
+ case 358: $function = 'GETPIVOTDATA'; break;
5855
+ case 359: $function = 'HYPERLINK'; break;
5856
+ case 361: $function = 'AVERAGEA'; break;
5857
+ case 362: $function = 'MAXA'; break;
5858
+ case 363: $function = 'MINA'; break;
5859
+ case 364: $function = 'STDEVPA'; break;
5860
+ case 365: $function = 'VARPA'; break;
5861
+ case 366: $function = 'STDEVA'; break;
5862
+ case 367: $function = 'VARA'; break;
5863
+ default:
5864
+ throw new PHPExcel_Reader_Exception('Unrecognized function in formula');
5865
+ break;
5866
+ }
5867
+ $data = array('function' => $function, 'args' => $args);
5868
+ break;
5869
+ case 0x23: // index to defined name
5870
+ case 0x43:
5871
+ case 0x63:
5872
+ $name = 'tName';
5873
+ $size = 5;
5874
+ // offset: 1; size: 2; one-based index to definedname record
5875
+ $definedNameIndex = self::_GetInt2d($formulaData, 1) - 1;
5876
+ // offset: 2; size: 2; not used
5877
+ $data = $this->_definedname[$definedNameIndex]['name'];
5878
+ break;
5879
+ case 0x24: // single cell reference e.g. A5
5880
+ case 0x44:
5881
+ case 0x64:
5882
+ $name = 'tRef';
5883
+ $size = 5;
5884
+ $data = $this->_readBIFF8CellAddress(substr($formulaData, 1, 4));
5885
+ break;
5886
+ case 0x25: // cell range reference to cells in the same sheet (2d)
5887
+ case 0x45:
5888
+ case 0x65:
5889
+ $name = 'tArea';
5890
+ $size = 9;
5891
+ $data = $this->_readBIFF8CellRangeAddress(substr($formulaData, 1, 8));
5892
+ break;
5893
+ case 0x26: // Constant reference sub-expression
5894
+ case 0x46:
5895
+ case 0x66:
5896
+ $name = 'tMemArea';
5897
+ // offset: 1; size: 4; not used
5898
+ // offset: 5; size: 2; size of the following subexpression
5899
+ $subSize = self::_GetInt2d($formulaData, 5);
5900
+ $size = 7 + $subSize;
5901
+ $data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
5902
+ break;
5903
+ case 0x27: // Deleted constant reference sub-expression
5904
+ case 0x47:
5905
+ case 0x67:
5906
+ $name = 'tMemErr';
5907
+ // offset: 1; size: 4; not used
5908
+ // offset: 5; size: 2; size of the following subexpression
5909
+ $subSize = self::_GetInt2d($formulaData, 5);
5910
+ $size = 7 + $subSize;
5911
+ $data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
5912
+ break;
5913
+ case 0x29: // Variable reference sub-expression
5914
+ case 0x49:
5915
+ case 0x69:
5916
+ $name = 'tMemFunc';
5917
+ // offset: 1; size: 2; size of the following sub-expression
5918
+ $subSize = self::_GetInt2d($formulaData, 1);
5919
+ $size = 3 + $subSize;
5920
+ $data = $this->_getFormulaFromData(substr($formulaData, 3, $subSize));
5921
+ break;
5922
+
5923
+ case 0x2C: // Relative 2d cell reference reference, used in shared formulas and some other places
5924
+ case 0x4C:
5925
+ case 0x6C:
5926
+ $name = 'tRefN';
5927
+ $size = 5;
5928
+ $data = $this->_readBIFF8CellAddressB(substr($formulaData, 1, 4), $baseCell);
5929
+ break;
5930
+
5931
+ case 0x2D: // Relative 2d range reference
5932
+ case 0x4D:
5933
+ case 0x6D:
5934
+ $name = 'tAreaN';
5935
+ $size = 9;
5936
+ $data = $this->_readBIFF8CellRangeAddressB(substr($formulaData, 1, 8), $baseCell);
5937
+ break;
5938
+
5939
+ case 0x39: // External name
5940
+ case 0x59:
5941
+ case 0x79:
5942
+ $name = 'tNameX';
5943
+ $size = 7;
5944
+ // offset: 1; size: 2; index to REF entry in EXTERNSHEET record
5945
+ // offset: 3; size: 2; one-based index to DEFINEDNAME or EXTERNNAME record
5946
+ $index = self::_GetInt2d($formulaData, 3);
5947
+ // assume index is to EXTERNNAME record
5948
+ $data = $this->_externalNames[$index - 1]['name'];
5949
+ // offset: 5; size: 2; not used
5950
+ break;
5951
+
5952
+ case 0x3A: // 3d reference to cell
5953
+ case 0x5A:
5954
+ case 0x7A:
5955
+ $name = 'tRef3d';
5956
+ $size = 7;
5957
+
5958
+ try {
5959
+ // offset: 1; size: 2; index to REF entry
5960
+ $sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
5961
+ // offset: 3; size: 4; cell address
5962
+ $cellAddress = $this->_readBIFF8CellAddress(substr($formulaData, 3, 4));
5963
+
5964
+ $data = "$sheetRange!$cellAddress";
5965
+ } catch (PHPExcel_Exception $e) {
5966
+ // deleted sheet reference
5967
+ $data = '#REF!';
5968
+ }
5969
+
5970
+ break;
5971
+ case 0x3B: // 3d reference to cell range
5972
+ case 0x5B:
5973
+ case 0x7B:
5974
+ $name = 'tArea3d';
5975
+ $size = 11;
5976
+
5977
+ try {
5978
+ // offset: 1; size: 2; index to REF entry
5979
+ $sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
5980
+ // offset: 3; size: 8; cell address
5981
+ $cellRangeAddress = $this->_readBIFF8CellRangeAddress(substr($formulaData, 3, 8));
5982
+
5983
+ $data = "$sheetRange!$cellRangeAddress";
5984
+ } catch (PHPExcel_Exception $e) {
5985
+ // deleted sheet reference
5986
+ $data = '#REF!';
5987
+ }
5988
+
5989
+ break;
5990
+ // Unknown cases // don't know how to deal with
5991
+ default:
5992
+ throw new PHPExcel_Reader_Exception('Unrecognized token ' . sprintf('%02X', $id) . ' in formula');
5993
+ break;
5994
+ }
5995
+
5996
+ return array(
5997
+ 'id' => $id,
5998
+ 'name' => $name,
5999
+ 'size' => $size,
6000
+ 'data' => $data,
6001
+ );
6002
+ }
6003
+
6004
+
6005
+ /**
6006
+ * Reads a cell address in BIFF8 e.g. 'A2' or '$A$2'
6007
+ * section 3.3.4
6008
+ *
6009
+ * @param string $cellAddressStructure
6010
+ * @return string
6011
+ */
6012
+ private function _readBIFF8CellAddress($cellAddressStructure)
6013
+ {
6014
+ // offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
6015
+ $row = self::_GetInt2d($cellAddressStructure, 0) + 1;
6016
+
6017
+ // offset: 2; size: 2; index to column or column offset + relative flags
6018
+
6019
+ // bit: 7-0; mask 0x00FF; column index
6020
+ $column = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($cellAddressStructure, 2));
6021
+
6022
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6023
+ if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) {
6024
+ $column = '$' . $column;
6025
+ }
6026
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6027
+ if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) {
6028
+ $row = '$' . $row;
6029
+ }
6030
+
6031
+ return $column . $row;
6032
+ }
6033
+
6034
+
6035
+ /**
6036
+ * Reads a cell address in BIFF8 for shared formulas. Uses positive and negative values for row and column
6037
+ * to indicate offsets from a base cell
6038
+ * section 3.3.4
6039
+ *
6040
+ * @param string $cellAddressStructure
6041
+ * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
6042
+ * @return string
6043
+ */
6044
+ private function _readBIFF8CellAddressB($cellAddressStructure, $baseCell = 'A1')
6045
+ {
6046
+ list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
6047
+ $baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
6048
+
6049
+ // offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
6050
+ $rowIndex = self::_GetInt2d($cellAddressStructure, 0);
6051
+ $row = self::_GetInt2d($cellAddressStructure, 0) + 1;
6052
+
6053
+ // offset: 2; size: 2; index to column or column offset + relative flags
6054
+
6055
+ // bit: 7-0; mask 0x00FF; column index
6056
+ $colIndex = 0x00FF & self::_GetInt2d($cellAddressStructure, 2);
6057
+
6058
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6059
+ if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) {
6060
+ $column = PHPExcel_Cell::stringFromColumnIndex($colIndex);
6061
+ $column = '$' . $column;
6062
+ } else {
6063
+ $colIndex = ($colIndex <= 127) ? $colIndex : $colIndex - 256;
6064
+ $column = PHPExcel_Cell::stringFromColumnIndex($baseCol + $colIndex);
6065
+ }
6066
+
6067
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6068
+ if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) {
6069
+ $row = '$' . $row;
6070
+ } else {
6071
+ $rowIndex = ($rowIndex <= 32767) ? $rowIndex : $rowIndex - 65536;
6072
+ $row = $baseRow + $rowIndex;
6073
+ }
6074
+
6075
+ return $column . $row;
6076
+ }
6077
+
6078
+
6079
+ /**
6080
+ * Reads a cell range address in BIFF5 e.g. 'A2:B6' or 'A1'
6081
+ * always fixed range
6082
+ * section 2.5.14
6083
+ *
6084
+ * @param string $subData
6085
+ * @return string
6086
+ * @throws PHPExcel_Reader_Exception
6087
+ */
6088
+ private function _readBIFF5CellRangeAddressFixed($subData)
6089
+ {
6090
+ // offset: 0; size: 2; index to first row
6091
+ $fr = self::_GetInt2d($subData, 0) + 1;
6092
+
6093
+ // offset: 2; size: 2; index to last row
6094
+ $lr = self::_GetInt2d($subData, 2) + 1;
6095
+
6096
+ // offset: 4; size: 1; index to first column
6097
+ $fc = ord($subData{4});
6098
+
6099
+ // offset: 5; size: 1; index to last column
6100
+ $lc = ord($subData{5});
6101
+
6102
+ // check values
6103
+ if ($fr > $lr || $fc > $lc) {
6104
+ throw new PHPExcel_Reader_Exception('Not a cell range address');
6105
+ }
6106
+
6107
+ // column index to letter
6108
+ $fc = PHPExcel_Cell::stringFromColumnIndex($fc);
6109
+ $lc = PHPExcel_Cell::stringFromColumnIndex($lc);
6110
+
6111
+ if ($fr == $lr and $fc == $lc) {
6112
+ return "$fc$fr";
6113
+ }
6114
+ return "$fc$fr:$lc$lr";
6115
+ }
6116
+
6117
+
6118
+ /**
6119
+ * Reads a cell range address in BIFF8 e.g. 'A2:B6' or 'A1'
6120
+ * always fixed range
6121
+ * section 2.5.14
6122
+ *
6123
+ * @param string $subData
6124
+ * @return string
6125
+ * @throws PHPExcel_Reader_Exception
6126
+ */
6127
+ private function _readBIFF8CellRangeAddressFixed($subData)
6128
+ {
6129
+ // offset: 0; size: 2; index to first row
6130
+ $fr = self::_GetInt2d($subData, 0) + 1;
6131
+
6132
+ // offset: 2; size: 2; index to last row
6133
+ $lr = self::_GetInt2d($subData, 2) + 1;
6134
+
6135
+ // offset: 4; size: 2; index to first column
6136
+ $fc = self::_GetInt2d($subData, 4);
6137
+
6138
+ // offset: 6; size: 2; index to last column
6139
+ $lc = self::_GetInt2d($subData, 6);
6140
+
6141
+ // check values
6142
+ if ($fr > $lr || $fc > $lc) {
6143
+ throw new PHPExcel_Reader_Exception('Not a cell range address');
6144
+ }
6145
+
6146
+ // column index to letter
6147
+ $fc = PHPExcel_Cell::stringFromColumnIndex($fc);
6148
+ $lc = PHPExcel_Cell::stringFromColumnIndex($lc);
6149
+
6150
+ if ($fr == $lr and $fc == $lc) {
6151
+ return "$fc$fr";
6152
+ }
6153
+ return "$fc$fr:$lc$lr";
6154
+ }
6155
+
6156
+
6157
+ /**
6158
+ * Reads a cell range address in BIFF8 e.g. 'A2:B6' or '$A$2:$B$6'
6159
+ * there are flags indicating whether column/row index is relative
6160
+ * section 3.3.4
6161
+ *
6162
+ * @param string $subData
6163
+ * @return string
6164
+ */
6165
+ private function _readBIFF8CellRangeAddress($subData)
6166
+ {
6167
+ // todo: if cell range is just a single cell, should this funciton
6168
+ // not just return e.g. 'A1' and not 'A1:A1' ?
6169
+
6170
+ // offset: 0; size: 2; index to first row (0... 65535) (or offset (-32768... 32767))
6171
+ $fr = self::_GetInt2d($subData, 0) + 1;
6172
+
6173
+ // offset: 2; size: 2; index to last row (0... 65535) (or offset (-32768... 32767))
6174
+ $lr = self::_GetInt2d($subData, 2) + 1;
6175
+
6176
+ // offset: 4; size: 2; index to first column or column offset + relative flags
6177
+
6178
+ // bit: 7-0; mask 0x00FF; column index
6179
+ $fc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 4));
6180
+
6181
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6182
+ if (!(0x4000 & self::_GetInt2d($subData, 4))) {
6183
+ $fc = '$' . $fc;
6184
+ }
6185
+
6186
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6187
+ if (!(0x8000 & self::_GetInt2d($subData, 4))) {
6188
+ $fr = '$' . $fr;
6189
+ }
6190
+
6191
+ // offset: 6; size: 2; index to last column or column offset + relative flags
6192
+
6193
+ // bit: 7-0; mask 0x00FF; column index
6194
+ $lc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 6));
6195
+
6196
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6197
+ if (!(0x4000 & self::_GetInt2d($subData, 6))) {
6198
+ $lc = '$' . $lc;
6199
+ }
6200
+
6201
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6202
+ if (!(0x8000 & self::_GetInt2d($subData, 6))) {
6203
+ $lr = '$' . $lr;
6204
+ }
6205
+
6206
+ return "$fc$fr:$lc$lr";
6207
+ }
6208
+
6209
+
6210
+ /**
6211
+ * Reads a cell range address in BIFF8 for shared formulas. Uses positive and negative values for row and column
6212
+ * to indicate offsets from a base cell
6213
+ * section 3.3.4
6214
+ *
6215
+ * @param string $subData
6216
+ * @param string $baseCell Base cell
6217
+ * @return string Cell range address
6218
+ */
6219
+ private function _readBIFF8CellRangeAddressB($subData, $baseCell = 'A1')
6220
+ {
6221
+ list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
6222
+ $baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
6223
+
6224
+ // TODO: if cell range is just a single cell, should this funciton
6225
+ // not just return e.g. 'A1' and not 'A1:A1' ?
6226
+
6227
+ // offset: 0; size: 2; first row
6228
+ $frIndex = self::_GetInt2d($subData, 0); // adjust below
6229
+
6230
+ // offset: 2; size: 2; relative index to first row (0... 65535) should be treated as offset (-32768... 32767)
6231
+ $lrIndex = self::_GetInt2d($subData, 2); // adjust below
6232
+
6233
+ // offset: 4; size: 2; first column with relative/absolute flags
6234
+
6235
+ // bit: 7-0; mask 0x00FF; column index
6236
+ $fcIndex = 0x00FF & self::_GetInt2d($subData, 4);
6237
+
6238
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6239
+ if (!(0x4000 & self::_GetInt2d($subData, 4))) {
6240
+ // absolute column index
6241
+ $fc = PHPExcel_Cell::stringFromColumnIndex($fcIndex);
6242
+ $fc = '$' . $fc;
6243
+ } else {
6244
+ // column offset
6245
+ $fcIndex = ($fcIndex <= 127) ? $fcIndex : $fcIndex - 256;
6246
+ $fc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $fcIndex);
6247
+ }
6248
+
6249
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6250
+ if (!(0x8000 & self::_GetInt2d($subData, 4))) {
6251
+ // absolute row index
6252
+ $fr = $frIndex + 1;
6253
+ $fr = '$' . $fr;
6254
+ } else {
6255
+ // row offset
6256
+ $frIndex = ($frIndex <= 32767) ? $frIndex : $frIndex - 65536;
6257
+ $fr = $baseRow + $frIndex;
6258
+ }
6259
+
6260
+ // offset: 6; size: 2; last column with relative/absolute flags
6261
+
6262
+ // bit: 7-0; mask 0x00FF; column index
6263
+ $lcIndex = 0x00FF & self::_GetInt2d($subData, 6);
6264
+ $lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
6265
+ $lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
6266
+
6267
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6268
+ if (!(0x4000 & self::_GetInt2d($subData, 6))) {
6269
+ // absolute column index
6270
+ $lc = PHPExcel_Cell::stringFromColumnIndex($lcIndex);
6271
+ $lc = '$' . $lc;
6272
+ } else {
6273
+ // column offset
6274
+ $lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
6275
+ $lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
6276
+ }
6277
+
6278
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6279
+ if (!(0x8000 & self::_GetInt2d($subData, 6))) {
6280
+ // absolute row index
6281
+ $lr = $lrIndex + 1;
6282
+ $lr = '$' . $lr;
6283
+ } else {
6284
+ // row offset
6285
+ $lrIndex = ($lrIndex <= 32767) ? $lrIndex : $lrIndex - 65536;
6286
+ $lr = $baseRow + $lrIndex;
6287
+ }
6288
+
6289
+ return "$fc$fr:$lc$lr";
6290
+ }
6291
+
6292
+
6293
+ /**
6294
+ * Read BIFF8 cell range address list
6295
+ * section 2.5.15
6296
+ *
6297
+ * @param string $subData
6298
+ * @return array
6299
+ */
6300
+ private function _readBIFF8CellRangeAddressList($subData)
6301
+ {
6302
+ $cellRangeAddresses = array();
6303
+
6304
+ // offset: 0; size: 2; number of the following cell range addresses
6305
+ $nm = self::_GetInt2d($subData, 0);
6306
+
6307
+ $offset = 2;
6308
+ // offset: 2; size: 8 * $nm; list of $nm (fixed) cell range addresses
6309
+ for ($i = 0; $i < $nm; ++$i) {
6310
+ $cellRangeAddresses[] = $this->_readBIFF8CellRangeAddressFixed(substr($subData, $offset, 8));
6311
+ $offset += 8;
6312
+ }
6313
+
6314
+ return array(
6315
+ 'size' => 2 + 8 * $nm,
6316
+ 'cellRangeAddresses' => $cellRangeAddresses,
6317
+ );
6318
+ }
6319
+
6320
+
6321
+ /**
6322
+ * Read BIFF5 cell range address list
6323
+ * section 2.5.15
6324
+ *
6325
+ * @param string $subData
6326
+ * @return array
6327
+ */
6328
+ private function _readBIFF5CellRangeAddressList($subData)
6329
+ {
6330
+ $cellRangeAddresses = array();
6331
+
6332
+ // offset: 0; size: 2; number of the following cell range addresses
6333
+ $nm = self::_GetInt2d($subData, 0);
6334
+
6335
+ $offset = 2;
6336
+ // offset: 2; size: 6 * $nm; list of $nm (fixed) cell range addresses
6337
+ for ($i = 0; $i < $nm; ++$i) {
6338
+ $cellRangeAddresses[] = $this->_readBIFF5CellRangeAddressFixed(substr($subData, $offset, 6));
6339
+ $offset += 6;
6340
+ }
6341
+
6342
+ return array(
6343
+ 'size' => 2 + 6 * $nm,
6344
+ 'cellRangeAddresses' => $cellRangeAddresses,
6345
+ );
6346
+ }
6347
+
6348
+
6349
+ /**
6350
+ * Get a sheet range like Sheet1:Sheet3 from REF index
6351
+ * Note: If there is only one sheet in the range, one gets e.g Sheet1
6352
+ * It can also happen that the REF structure uses the -1 (FFFF) code to indicate deleted sheets,
6353
+ * in which case an PHPExcel_Reader_Exception is thrown
6354
+ *
6355
+ * @param int $index
6356
+ * @return string|false
6357
+ * @throws PHPExcel_Reader_Exception
6358
+ */
6359
+ private function _readSheetRangeByRefIndex($index)
6360
+ {
6361
+ if (isset($this->_ref[$index])) {
6362
+
6363
+ $type = $this->_externalBooks[$this->_ref[$index]['externalBookIndex']]['type'];
6364
+
6365
+ switch ($type) {
6366
+ case 'internal':
6367
+ // check if we have a deleted 3d reference
6368
+ if ($this->_ref[$index]['firstSheetIndex'] == 0xFFFF or $this->_ref[$index]['lastSheetIndex'] == 0xFFFF) {
6369
+ throw new PHPExcel_Reader_Exception('Deleted sheet reference');
6370
+ }
6371
+
6372
+ // we have normal sheet range (collapsed or uncollapsed)
6373
+ $firstSheetName = $this->_sheets[$this->_ref[$index]['firstSheetIndex']]['name'];
6374
+ $lastSheetName = $this->_sheets[$this->_ref[$index]['lastSheetIndex']]['name'];
6375
+
6376
+ if ($firstSheetName == $lastSheetName) {
6377
+ // collapsed sheet range
6378
+ $sheetRange = $firstSheetName;
6379
+ } else {
6380
+ $sheetRange = "$firstSheetName:$lastSheetName";
6381
+ }
6382
+
6383
+ // escape the single-quotes
6384
+ $sheetRange = str_replace("'", "''", $sheetRange);
6385
+
6386
+ // if there are special characters, we need to enclose the range in single-quotes
6387
+ // todo: check if we have identified the whole set of special characters
6388
+ // it seems that the following characters are not accepted for sheet names
6389
+ // and we may assume that they are not present: []*/:\?
6390
+ if (preg_match("/[ !\"@#£$%&{()}<>=+'|^,;-]/", $sheetRange)) {
6391
+ $sheetRange = "'$sheetRange'";
6392
+ }
6393
+
6394
+ return $sheetRange;
6395
+ break;
6396
+
6397
+ default:
6398
+ // TODO: external sheet support
6399
+ throw new PHPExcel_Reader_Exception('Excel5 reader only supports internal sheets in fomulas');
6400
+ break;
6401
+ }
6402
+ }
6403
+ return false;
6404
+ }
6405
+
6406
+
6407
+ /**
6408
+ * read BIFF8 constant value array from array data
6409
+ * returns e.g. array('value' => '{1,2;3,4}', 'size' => 40}
6410
+ * section 2.5.8
6411
+ *
6412
+ * @param string $arrayData
6413
+ * @return array
6414
+ */
6415
+ private static function _readBIFF8ConstantArray($arrayData)
6416
+ {
6417
+ // offset: 0; size: 1; number of columns decreased by 1
6418
+ $nc = ord($arrayData[0]);
6419
+
6420
+ // offset: 1; size: 2; number of rows decreased by 1
6421
+ $nr = self::_GetInt2d($arrayData, 1);
6422
+ $size = 3; // initialize
6423
+ $arrayData = substr($arrayData, 3);
6424
+
6425
+ // offset: 3; size: var; list of ($nc + 1) * ($nr + 1) constant values
6426
+ $matrixChunks = array();
6427
+ for ($r = 1; $r <= $nr + 1; ++$r) {
6428
+ $items = array();
6429
+ for ($c = 1; $c <= $nc + 1; ++$c) {
6430
+ $constant = self::_readBIFF8Constant($arrayData);
6431
+ $items[] = $constant['value'];
6432
+ $arrayData = substr($arrayData, $constant['size']);
6433
+ $size += $constant['size'];
6434
+ }
6435
+ $matrixChunks[] = implode(',', $items); // looks like e.g. '1,"hello"'
6436
+ }
6437
+ $matrix = '{' . implode(';', $matrixChunks) . '}';
6438
+
6439
+ return array(
6440
+ 'value' => $matrix,
6441
+ 'size' => $size,
6442
+ );
6443
+ }
6444
+
6445
+
6446
+ /**
6447
+ * read BIFF8 constant value which may be 'Empty Value', 'Number', 'String Value', 'Boolean Value', 'Error Value'
6448
+ * section 2.5.7
6449
+ * returns e.g. array('value' => '5', 'size' => 9)
6450
+ *
6451
+ * @param string $valueData
6452
+ * @return array
6453
+ */
6454
+ private static function _readBIFF8Constant($valueData)
6455
+ {
6456
+ // offset: 0; size: 1; identifier for type of constant
6457
+ $identifier = ord($valueData[0]);
6458
+
6459
+ switch ($identifier) {
6460
+ case 0x00: // empty constant (what is this?)
6461
+ $value = '';
6462
+ $size = 9;
6463
+ break;
6464
+ case 0x01: // number
6465
+ // offset: 1; size: 8; IEEE 754 floating-point value
6466
+ $value = self::_extractNumber(substr($valueData, 1, 8));
6467
+ $size = 9;
6468
+ break;
6469
+ case 0x02: // string value
6470
+ // offset: 1; size: var; Unicode string, 16-bit string length
6471
+ $string = self::_readUnicodeStringLong(substr($valueData, 1));
6472
+ $value = '"' . $string['value'] . '"';
6473
+ $size = 1 + $string['size'];
6474
+ break;
6475
+ case 0x04: // boolean
6476
+ // offset: 1; size: 1; 0 = FALSE, 1 = TRUE
6477
+ if (ord($valueData[1])) {
6478
+ $value = 'TRUE';
6479
+ } else {
6480
+ $value = 'FALSE';
6481
+ }
6482
+ $size = 9;
6483
+ break;
6484
+ case 0x10: // error code
6485
+ // offset: 1; size: 1; error code
6486
+ $value = self::_mapErrorCode(ord($valueData[1]));
6487
+ $size = 9;
6488
+ break;
6489
+ }
6490
+ return array(
6491
+ 'value' => $value,
6492
+ 'size' => $size,
6493
+ );
6494
+ }
6495
+
6496
+
6497
+ /**
6498
+ * Extract RGB color
6499
+ * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.4
6500
+ *
6501
+ * @param string $rgb Encoded RGB value (4 bytes)
6502
+ * @return array
6503
+ */
6504
+ private static function _readRGB($rgb)
6505
+ {
6506
+ // offset: 0; size 1; Red component
6507
+ $r = ord($rgb{0});
6508
+
6509
+ // offset: 1; size: 1; Green component
6510
+ $g = ord($rgb{1});
6511
+
6512
+ // offset: 2; size: 1; Blue component
6513
+ $b = ord($rgb{2});
6514
+
6515
+ // HEX notation, e.g. 'FF00FC'
6516
+ $rgb = sprintf('%02X%02X%02X', $r, $g, $b);
6517
+
6518
+ return array('rgb' => $rgb);
6519
+ }
6520
+
6521
+
6522
+ /**
6523
+ * Read byte string (8-bit string length)
6524
+ * OpenOffice documentation: 2.5.2
6525
+ *
6526
+ * @param string $subData
6527
+ * @return array
6528
+ */
6529
+ private function _readByteStringShort($subData)
6530
+ {
6531
+ // offset: 0; size: 1; length of the string (character count)
6532
+ $ln = ord($subData[0]);
6533
+
6534
+ // offset: 1: size: var; character array (8-bit characters)
6535
+ $value = $this->_decodeCodepage(substr($subData, 1, $ln));
6536
+
6537
+ return array(
6538
+ 'value' => $value,
6539
+ 'size' => 1 + $ln, // size in bytes of data structure
6540
+ );
6541
+ }
6542
+
6543
+
6544
+ /**
6545
+ * Read byte string (16-bit string length)
6546
+ * OpenOffice documentation: 2.5.2
6547
+ *
6548
+ * @param string $subData
6549
+ * @return array
6550
+ */
6551
+ private function _readByteStringLong($subData)
6552
+ {
6553
+ // offset: 0; size: 2; length of the string (character count)
6554
+ $ln = self::_GetInt2d($subData, 0);
6555
+
6556
+ // offset: 2: size: var; character array (8-bit characters)
6557
+ $value = $this->_decodeCodepage(substr($subData, 2));
6558
+
6559
+ //return $string;
6560
+ return array(
6561
+ 'value' => $value,
6562
+ 'size' => 2 + $ln, // size in bytes of data structure
6563
+ );
6564
+ }
6565
+
6566
+
6567
+ /**
6568
+ * Extracts an Excel Unicode short string (8-bit string length)
6569
+ * OpenOffice documentation: 2.5.3
6570
+ * function will automatically find out where the Unicode string ends.
6571
+ *
6572
+ * @param string $subData
6573
+ * @return array
6574
+ */
6575
+ private static function _readUnicodeStringShort($subData)
6576
+ {
6577
+ $value = '';
6578
+
6579
+ // offset: 0: size: 1; length of the string (character count)
6580
+ $characterCount = ord($subData[0]);
6581
+
6582
+ $string = self::_readUnicodeString(substr($subData, 1), $characterCount);
6583
+
6584
+ // add 1 for the string length
6585
+ $string['size'] += 1;
6586
+
6587
+ return $string;
6588
+ }
6589
+
6590
+
6591
+ /**
6592
+ * Extracts an Excel Unicode long string (16-bit string length)
6593
+ * OpenOffice documentation: 2.5.3
6594
+ * this function is under construction, needs to support rich text, and Asian phonetic settings
6595
+ *
6596
+ * @param string $subData
6597
+ * @return array
6598
+ */
6599
+ private static function _readUnicodeStringLong($subData)
6600
+ {
6601
+ $value = '';
6602
+
6603
+ // offset: 0: size: 2; length of the string (character count)
6604
+ $characterCount = self::_GetInt2d($subData, 0);
6605
+
6606
+ $string = self::_readUnicodeString(substr($subData, 2), $characterCount);
6607
+
6608
+ // add 2 for the string length
6609
+ $string['size'] += 2;
6610
+
6611
+ return $string;
6612
+ }
6613
+
6614
+
6615
+ /**
6616
+ * Read Unicode string with no string length field, but with known character count
6617
+ * this function is under construction, needs to support rich text, and Asian phonetic settings
6618
+ * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.3
6619
+ *
6620
+ * @param string $subData
6621
+ * @param int $characterCount
6622
+ * @return array
6623
+ */
6624
+ private static function _readUnicodeString($subData, $characterCount)
6625
+ {
6626
+ $value = '';
6627
+
6628
+ // offset: 0: size: 1; option flags
6629
+
6630
+ // bit: 0; mask: 0x01; character compression (0 = compressed 8-bit, 1 = uncompressed 16-bit)
6631
+ $isCompressed = !((0x01 & ord($subData[0])) >> 0);
6632
+
6633
+ // bit: 2; mask: 0x04; Asian phonetic settings
6634
+ $hasAsian = (0x04) & ord($subData[0]) >> 2;
6635
+
6636
+ // bit: 3; mask: 0x08; Rich-Text settings
6637
+ $hasRichText = (0x08) & ord($subData[0]) >> 3;
6638
+
6639
+ // offset: 1: size: var; character array
6640
+ // this offset assumes richtext and Asian phonetic settings are off which is generally wrong
6641
+ // needs to be fixed
6642
+ $value = self::_encodeUTF16(substr($subData, 1, $isCompressed ? $characterCount : 2 * $characterCount), $isCompressed);
6643
+
6644
+ return array(
6645
+ 'value' => $value,
6646
+ 'size' => $isCompressed ? 1 + $characterCount : 1 + 2 * $characterCount, // the size in bytes including the option flags
6647
+ );
6648
+ }
6649
+
6650
+
6651
+ /**
6652
+ * Convert UTF-8 string to string surounded by double quotes. Used for explicit string tokens in formulas.
6653
+ * Example: hello"world --> "hello""world"
6654
+ *
6655
+ * @param string $value UTF-8 encoded string
6656
+ * @return string
6657
+ */
6658
+ private static function _UTF8toExcelDoubleQuoted($value)
6659
+ {
6660
+ return '"' . str_replace('"', '""', $value) . '"';
6661
+ }
6662
+
6663
+
6664
+ /**
6665
+ * Reads first 8 bytes of a string and return IEEE 754 float
6666
+ *
6667
+ * @param string $data Binary string that is at least 8 bytes long
6668
+ * @return float
6669
+ */
6670
+ private static function _extractNumber($data)
6671
+ {
6672
+ $rknumhigh = self::_GetInt4d($data, 4);
6673
+ $rknumlow = self::_GetInt4d($data, 0);
6674
+ $sign = ($rknumhigh & 0x80000000) >> 31;
6675
+ $exp = (($rknumhigh & 0x7ff00000) >> 20) - 1023;
6676
+ $mantissa = (0x100000 | ($rknumhigh & 0x000fffff));
6677
+ $mantissalow1 = ($rknumlow & 0x80000000) >> 31;
6678
+ $mantissalow2 = ($rknumlow & 0x7fffffff);
6679
+ $value = $mantissa / pow( 2 , (20 - $exp));
6680
+
6681
+ if ($mantissalow1 != 0) {
6682
+ $value += 1 / pow (2 , (21 - $exp));
6683
+ }
6684
+
6685
+ $value += $mantissalow2 / pow (2 , (52 - $exp));
6686
+ if ($sign) {
6687
+ $value *= -1;
6688
+ }
6689
+
6690
+ return $value;
6691
+ }
6692
+
6693
+
6694
+ private static function _GetIEEE754($rknum)
6695
+ {
6696
+ if (($rknum & 0x02) != 0) {
6697
+ $value = $rknum >> 2;
6698
+ } else {
6699
+ // changes by mmp, info on IEEE754 encoding from
6700
+ // research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
6701
+ // The RK format calls for using only the most significant 30 bits
6702
+ // of the 64 bit floating point value. The other 34 bits are assumed
6703
+ // to be 0 so we use the upper 30 bits of $rknum as follows...
6704
+ $sign = ($rknum & 0x80000000) >> 31;
6705
+ $exp = ($rknum & 0x7ff00000) >> 20;
6706
+ $mantissa = (0x100000 | ($rknum & 0x000ffffc));
6707
+ $value = $mantissa / pow( 2 , (20- ($exp - 1023)));
6708
+ if ($sign) {
6709
+ $value = -1 * $value;
6710
+ }
6711
+ //end of changes by mmp
6712
+ }
6713
+ if (($rknum & 0x01) != 0) {
6714
+ $value /= 100;
6715
+ }
6716
+ return $value;
6717
+ }
6718
+
6719
+
6720
+ /**
6721
+ * Get UTF-8 string from (compressed or uncompressed) UTF-16 string
6722
+ *
6723
+ * @param string $string
6724
+ * @param bool $compressed
6725
+ * @return string
6726
+ */
6727
+ private static function _encodeUTF16($string, $compressed = '')
6728
+ {
6729
+ if ($compressed) {
6730
+ $string = self::_uncompressByteString($string);
6731
+ }
6732
+
6733
+ return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', 'UTF-16LE');
6734
+ }
6735
+
6736
+
6737
+ /**
6738
+ * Convert UTF-16 string in compressed notation to uncompressed form. Only used for BIFF8.
6739
+ *
6740
+ * @param string $string
6741
+ * @return string
6742
+ */
6743
+ private static function _uncompressByteString($string)
6744
+ {
6745
+ $uncompressedString = '';
6746
+ $strLen = strlen($string);
6747
+ for ($i = 0; $i < $strLen; ++$i) {
6748
+ $uncompressedString .= $string[$i] . "\0";
6749
+ }
6750
+
6751
+ return $uncompressedString;
6752
+ }
6753
+
6754
+
6755
+ /**
6756
+ * Convert string to UTF-8. Only used for BIFF5.
6757
+ *
6758
+ * @param string $string
6759
+ * @return string
6760
+ */
6761
+ private function _decodeCodepage($string)
6762
+ {
6763
+ return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', $this->_codepage);
6764
+ }
6765
+
6766
+
6767
+ /**
6768
+ * Read 16-bit unsigned integer
6769
+ *
6770
+ * @param string $data
6771
+ * @param int $pos
6772
+ * @return int
6773
+ */
6774
+ public static function _GetInt2d($data, $pos)
6775
+ {
6776
+ return ord($data[$pos]) | (ord($data[$pos+1]) << 8);
6777
+ }
6778
+
6779
+
6780
+ /**
6781
+ * Read 32-bit signed integer
6782
+ *
6783
+ * @param string $data
6784
+ * @param int $pos
6785
+ * @return int
6786
+ */
6787
+ public static function _GetInt4d($data, $pos)
6788
+ {
6789
+ // FIX: represent numbers correctly on 64-bit system
6790
+ // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
6791
+ // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
6792
+ $_or_24 = ord($data[$pos + 3]);
6793
+ if ($_or_24 >= 128) {
6794
+ // negative number
6795
+ $_ord_24 = -abs((256 - $_or_24) << 24);
6796
+ } else {
6797
+ $_ord_24 = ($_or_24 & 127) << 24;
6798
+ }
6799
+ return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $_ord_24;
6800
+ }
6801
+
6802
+
6803
+ /**
6804
+ * Read color
6805
+ *
6806
+ * @param int $color Indexed color
6807
+ * @param array $palette Color palette
6808
+ * @return array RGB color value, example: array('rgb' => 'FF0000')
6809
+ */
6810
+ private static function _readColor($color,$palette,$version)
6811
+ {
6812
+ if ($color <= 0x07 || $color >= 0x40) {
6813
+ // special built-in color
6814
+ return self::_mapBuiltInColor($color);
6815
+ } elseif (isset($palette) && isset($palette[$color - 8])) {
6816
+ // palette color, color index 0x08 maps to pallete index 0
6817
+ return $palette[$color - 8];
6818
+ } else {
6819
+ // default color table
6820
+ if ($version == self::XLS_BIFF8) {
6821
+ return self::_mapColor($color);
6822
+ } else {
6823
+ // BIFF5
6824
+ return self::_mapColorBIFF5($color);
6825
+ }
6826
+ }
6827
+
6828
+ return $color;
6829
+ }
6830
+
6831
+
6832
+ /**
6833
+ * Map border style
6834
+ * OpenOffice documentation: 2.5.11
6835
+ *
6836
+ * @param int $index
6837
+ * @return string
6838
+ */
6839
+ private static function _mapBorderStyle($index)
6840
+ {
6841
+ switch ($index) {
6842
+ case 0x00: return PHPExcel_Style_Border::BORDER_NONE;
6843
+ case 0x01: return PHPExcel_Style_Border::BORDER_THIN;
6844
+ case 0x02: return PHPExcel_Style_Border::BORDER_MEDIUM;
6845
+ case 0x03: return PHPExcel_Style_Border::BORDER_DASHED;
6846
+ case 0x04: return PHPExcel_Style_Border::BORDER_DOTTED;
6847
+ case 0x05: return PHPExcel_Style_Border::BORDER_THICK;
6848
+ case 0x06: return PHPExcel_Style_Border::BORDER_DOUBLE;
6849
+ case 0x07: return PHPExcel_Style_Border::BORDER_HAIR;
6850
+ case 0x08: return PHPExcel_Style_Border::BORDER_MEDIUMDASHED;
6851
+ case 0x09: return PHPExcel_Style_Border::BORDER_DASHDOT;
6852
+ case 0x0A: return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT;
6853
+ case 0x0B: return PHPExcel_Style_Border::BORDER_DASHDOTDOT;
6854
+ case 0x0C: return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT;
6855
+ case 0x0D: return PHPExcel_Style_Border::BORDER_SLANTDASHDOT;
6856
+ default: return PHPExcel_Style_Border::BORDER_NONE;
6857
+ }
6858
+ }
6859
+
6860
+
6861
+ /**
6862
+ * Get fill pattern from index
6863
+ * OpenOffice documentation: 2.5.12
6864
+ *
6865
+ * @param int $index
6866
+ * @return string
6867
+ */
6868
+ private static function _mapFillPattern($index)
6869
+ {
6870
+ switch ($index) {
6871
+ case 0x00: return PHPExcel_Style_Fill::FILL_NONE;
6872
+ case 0x01: return PHPExcel_Style_Fill::FILL_SOLID;
6873
+ case 0x02: return PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY;
6874
+ case 0x03: return PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY;
6875
+ case 0x04: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY;
6876
+ case 0x05: return PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL;
6877
+ case 0x06: return PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL;
6878
+ case 0x07: return PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN;
6879
+ case 0x08: return PHPExcel_Style_Fill::FILL_PATTERN_DARKUP;
6880
+ case 0x09: return PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID;
6881
+ case 0x0A: return PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS;
6882
+ case 0x0B: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL;
6883
+ case 0x0C: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL;
6884
+ case 0x0D: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN;
6885
+ case 0x0E: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP;
6886
+ case 0x0F: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID;
6887
+ case 0x10: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS;
6888
+ case 0x11: return PHPExcel_Style_Fill::FILL_PATTERN_GRAY125;
6889
+ case 0x12: return PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625;
6890
+ default: return PHPExcel_Style_Fill::FILL_NONE;
6891
+ }
6892
+ }
6893
+
6894
+
6895
+ /**
6896
+ * Map error code, e.g. '#N/A'
6897
+ *
6898
+ * @param int $subData
6899
+ * @return string
6900
+ */
6901
+ private static function _mapErrorCode($subData)
6902
+ {
6903
+ switch ($subData) {
6904
+ case 0x00: return '#NULL!'; break;
6905
+ case 0x07: return '#DIV/0!'; break;
6906
+ case 0x0F: return '#VALUE!'; break;
6907
+ case 0x17: return '#REF!'; break;
6908
+ case 0x1D: return '#NAME?'; break;
6909
+ case 0x24: return '#NUM!'; break;
6910
+ case 0x2A: return '#N/A'; break;
6911
+ default: return false;
6912
+ }
6913
+ }
6914
+
6915
+
6916
+ /**
6917
+ * Map built-in color to RGB value
6918
+ *
6919
+ * @param int $color Indexed color
6920
+ * @return array
6921
+ */
6922
+ private static function _mapBuiltInColor($color)
6923
+ {
6924
+ switch ($color) {
6925
+ case 0x00: return array('rgb' => '000000');
6926
+ case 0x01: return array('rgb' => 'FFFFFF');
6927
+ case 0x02: return array('rgb' => 'FF0000');
6928
+ case 0x03: return array('rgb' => '00FF00');
6929
+ case 0x04: return array('rgb' => '0000FF');
6930
+ case 0x05: return array('rgb' => 'FFFF00');
6931
+ case 0x06: return array('rgb' => 'FF00FF');
6932
+ case 0x07: return array('rgb' => '00FFFF');
6933
+ case 0x40: return array('rgb' => '000000'); // system window text color
6934
+ case 0x41: return array('rgb' => 'FFFFFF'); // system window background color
6935
+ default: return array('rgb' => '000000');
6936
+ }
6937
+ }
6938
+
6939
+
6940
+ /**
6941
+ * Map color array from BIFF5 built-in color index
6942
+ *
6943
+ * @param int $subData
6944
+ * @return array
6945
+ */
6946
+ private static function _mapColorBIFF5($subData)
6947
+ {
6948
+ switch ($subData) {
6949
+ case 0x08: return array('rgb' => '000000');
6950
+ case 0x09: return array('rgb' => 'FFFFFF');
6951
+ case 0x0A: return array('rgb' => 'FF0000');
6952
+ case 0x0B: return array('rgb' => '00FF00');
6953
+ case 0x0C: return array('rgb' => '0000FF');
6954
+ case 0x0D: return array('rgb' => 'FFFF00');
6955
+ case 0x0E: return array('rgb' => 'FF00FF');
6956
+ case 0x0F: return array('rgb' => '00FFFF');
6957
+ case 0x10: return array('rgb' => '800000');
6958
+ case 0x11: return array('rgb' => '008000');
6959
+ case 0x12: return array('rgb' => '000080');
6960
+ case 0x13: return array('rgb' => '808000');
6961
+ case 0x14: return array('rgb' => '800080');
6962
+ case 0x15: return array('rgb' => '008080');
6963
+ case 0x16: return array('rgb' => 'C0C0C0');
6964
+ case 0x17: return array('rgb' => '808080');
6965
+ case 0x18: return array('rgb' => '8080FF');
6966
+ case 0x19: return array('rgb' => '802060');
6967
+ case 0x1A: return array('rgb' => 'FFFFC0');
6968
+ case 0x1B: return array('rgb' => 'A0E0F0');
6969
+ case 0x1C: return array('rgb' => '600080');
6970
+ case 0x1D: return array('rgb' => 'FF8080');
6971
+ case 0x1E: return array('rgb' => '0080C0');
6972
+ case 0x1F: return array('rgb' => 'C0C0FF');
6973
+ case 0x20: return array('rgb' => '000080');
6974
+ case 0x21: return array('rgb' => 'FF00FF');
6975
+ case 0x22: return array('rgb' => 'FFFF00');
6976
+ case 0x23: return array('rgb' => '00FFFF');
6977
+ case 0x24: return array('rgb' => '800080');
6978
+ case 0x25: return array('rgb' => '800000');
6979
+ case 0x26: return array('rgb' => '008080');
6980
+ case 0x27: return array('rgb' => '0000FF');
6981
+ case 0x28: return array('rgb' => '00CFFF');
6982
+ case 0x29: return array('rgb' => '69FFFF');
6983
+ case 0x2A: return array('rgb' => 'E0FFE0');
6984
+ case 0x2B: return array('rgb' => 'FFFF80');
6985
+ case 0x2C: return array('rgb' => 'A6CAF0');
6986
+ case 0x2D: return array('rgb' => 'DD9CB3');
6987
+ case 0x2E: return array('rgb' => 'B38FEE');
6988
+ case 0x2F: return array('rgb' => 'E3E3E3');
6989
+ case 0x30: return array('rgb' => '2A6FF9');
6990
+ case 0x31: return array('rgb' => '3FB8CD');
6991
+ case 0x32: return array('rgb' => '488436');
6992
+ case 0x33: return array('rgb' => '958C41');
6993
+ case 0x34: return array('rgb' => '8E5E42');
6994
+ case 0x35: return array('rgb' => 'A0627A');
6995
+ case 0x36: return array('rgb' => '624FAC');
6996
+ case 0x37: return array('rgb' => '969696');
6997
+ case 0x38: return array('rgb' => '1D2FBE');
6998
+ case 0x39: return array('rgb' => '286676');
6999
+ case 0x3A: return array('rgb' => '004500');
7000
+ case 0x3B: return array('rgb' => '453E01');
7001
+ case 0x3C: return array('rgb' => '6A2813');
7002
+ case 0x3D: return array('rgb' => '85396A');
7003
+ case 0x3E: return array('rgb' => '4A3285');
7004
+ case 0x3F: return array('rgb' => '424242');
7005
+ default: return array('rgb' => '000000');
7006
+ }
7007
+ }
7008
+
7009
+
7010
+ /**
7011
+ * Map color array from BIFF8 built-in color index
7012
+ *
7013
+ * @param int $subData
7014
+ * @return array
7015
+ */
7016
+ private static function _mapColor($subData)
7017
+ {
7018
+ switch ($subData) {
7019
+ case 0x08: return array('rgb' => '000000');
7020
+ case 0x09: return array('rgb' => 'FFFFFF');
7021
+ case 0x0A: return array('rgb' => 'FF0000');
7022
+ case 0x0B: return array('rgb' => '00FF00');
7023
+ case 0x0C: return array('rgb' => '0000FF');
7024
+ case 0x0D: return array('rgb' => 'FFFF00');
7025
+ case 0x0E: return array('rgb' => 'FF00FF');
7026
+ case 0x0F: return array('rgb' => '00FFFF');
7027
+ case 0x10: return array('rgb' => '800000');
7028
+ case 0x11: return array('rgb' => '008000');
7029
+ case 0x12: return array('rgb' => '000080');
7030
+ case 0x13: return array('rgb' => '808000');
7031
+ case 0x14: return array('rgb' => '800080');
7032
+ case 0x15: return array('rgb' => '008080');
7033
+ case 0x16: return array('rgb' => 'C0C0C0');
7034
+ case 0x17: return array('rgb' => '808080');
7035
+ case 0x18: return array('rgb' => '9999FF');
7036
+ case 0x19: return array('rgb' => '993366');
7037
+ case 0x1A: return array('rgb' => 'FFFFCC');
7038
+ case 0x1B: return array('rgb' => 'CCFFFF');
7039
+ case 0x1C: return array('rgb' => '660066');
7040
+ case 0x1D: return array('rgb' => 'FF8080');
7041
+ case 0x1E: return array('rgb' => '0066CC');
7042
+ case 0x1F: return array('rgb' => 'CCCCFF');
7043
+ case 0x20: return array('rgb' => '000080');
7044
+ case 0x21: return array('rgb' => 'FF00FF');
7045
+ case 0x22: return array('rgb' => 'FFFF00');
7046
+ case 0x23: return array('rgb' => '00FFFF');
7047
+ case 0x24: return array('rgb' => '800080');
7048
+ case 0x25: return array('rgb' => '800000');
7049
+ case 0x26: return array('rgb' => '008080');
7050
+ case 0x27: return array('rgb' => '0000FF');
7051
+ case 0x28: return array('rgb' => '00CCFF');
7052
+ case 0x29: return array('rgb' => 'CCFFFF');
7053
+ case 0x2A: return array('rgb' => 'CCFFCC');
7054
+ case 0x2B: return array('rgb' => 'FFFF99');
7055
+ case 0x2C: return array('rgb' => '99CCFF');
7056
+ case 0x2D: return array('rgb' => 'FF99CC');
7057
+ case 0x2E: return array('rgb' => 'CC99FF');
7058
+ case 0x2F: return array('rgb' => 'FFCC99');
7059
+ case 0x30: return array('rgb' => '3366FF');
7060
+ case 0x31: return array('rgb' => '33CCCC');
7061
+ case 0x32: return array('rgb' => '99CC00');
7062
+ case 0x33: return array('rgb' => 'FFCC00');
7063
+ case 0x34: return array('rgb' => 'FF9900');
7064
+ case 0x35: return array('rgb' => 'FF6600');
7065
+ case 0x36: return array('rgb' => '666699');
7066
+ case 0x37: return array('rgb' => '969696');
7067
+ case 0x38: return array('rgb' => '003366');
7068
+ case 0x39: return array('rgb' => '339966');
7069
+ case 0x3A: return array('rgb' => '003300');
7070
+ case 0x3B: return array('rgb' => '333300');
7071
+ case 0x3C: return array('rgb' => '993300');
7072
+ case 0x3D: return array('rgb' => '993366');
7073
+ case 0x3E: return array('rgb' => '333399');
7074
+ case 0x3F: return array('rgb' => '333333');
7075
+ default: return array('rgb' => '000000');
7076
+ }
7077
+ }
7078
+
7079
+
7080
+ private function _parseRichText($is = '') {
7081
+ $value = new PHPExcel_RichText();
7082
+
7083
+ $value->createText($is);
7084
+
7085
+ return $value;
7086
+ }
7087
+
7088
+ }
{libraries → classes}/PHPExcel/Reader/Excel5/Escher.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/Excel5/MD5.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/Excel5/RC4.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/Exception.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/Gnumeric.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/HTML.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/IReadFilter.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/IReader.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/OOCalc.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Reader/SYLK.php RENAMED
File without changes
{libraries → classes}/PHPExcel/ReferenceHelper.php RENAMED
File without changes
{libraries → classes}/PHPExcel/RichText.php RENAMED
File without changes
{libraries → classes}/PHPExcel/RichText/ITextElement.php RENAMED
File without changes
{libraries → classes}/PHPExcel/RichText/Run.php RENAMED
File without changes
{libraries → classes}/PHPExcel/RichText/TextElement.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Settings.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/CodePage.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Date.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Drawing.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Escher.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Escher/DgContainer.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Escher/DggContainer.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Excel5.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/File.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/Font.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/JAMA/CHANGELOG.TXT RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/JAMA/CholeskyDecomposition.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/JAMA/EigenvalueDecomposition.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/JAMA/LUDecomposition.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/JAMA/Matrix.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/JAMA/QRDecomposition.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/JAMA/SingularValueDecomposition.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/JAMA/utils/Error.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/JAMA/utils/Maths.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/OLE.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/OLE/ChainedBlockStream.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/OLE/PPS.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/OLE/PPS/File.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/OLE/PPS/Root.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/OLERead.php RENAMED
File without changes
{libraries → classes}/PHPExcel/Shared/PCLZip/gnu-lgpl.txt RENAMED
@@ -1,504 +1,504 @@
1
- GNU LESSER GENERAL PUBLIC LICENSE
2
- Version 2.1, February 1999
3
-
4
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6
- Everyone is permitted to copy and distribute verbatim copies
7
- of this license document, but changing it is not allowed.
8
-
9
- [This is the first released version of the Lesser GPL. It also counts
10
- as the successor of the GNU Library Public License, version 2, hence
11
- the version number 2.1.]
12
-
13
- Preamble
14
-
15
- The licenses for most software are designed to take away your
16
- freedom to share and change it. By contrast, the GNU General Public
17
- Licenses are intended to guarantee your freedom to share and change
18
- free software--to make sure the software is free for all its users.
19
-
20
- This license, the Lesser General Public License, applies to some
21
- specially designated software packages--typically libraries--of the
22
- Free Software Foundation and other authors who decide to use it. You
23
- can use it too, but we suggest you first think carefully about whether
24
- this license or the ordinary General Public License is the better
25
- strategy to use in any particular case, based on the explanations below.
26
-
27
- When we speak of free software, we are referring to freedom of use,
28
- not price. Our General Public Licenses are designed to make sure that
29
- you have the freedom to distribute copies of free software (and charge
30
- for this service if you wish); that you receive source code or can get
31
- it if you want it; that you can change the software and use pieces of
32
- it in new free programs; and that you are informed that you can do
33
- these things.
34
-
35
- To protect your rights, we need to make restrictions that forbid
36
- distributors to deny you these rights or to ask you to surrender these
37
- rights. These restrictions translate to certain responsibilities for
38
- you if you distribute copies of the library or if you modify it.
39
-
40
- For example, if you distribute copies of the library, whether gratis
41
- or for a fee, you must give the recipients all the rights that we gave
42
- you. You must make sure that they, too, receive or can get the source
43
- code. If you link other code with the library, you must provide
44
- complete object files to the recipients, so that they can relink them
45
- with the library after making changes to the library and recompiling
46
- it. And you must show them these terms so they know their rights.
47
-
48
- We protect your rights with a two-step method: (1) we copyright the
49
- library, and (2) we offer you this license, which gives you legal
50
- permission to copy, distribute and/or modify the library.
51
-
52
- To protect each distributor, we want to make it very clear that
53
- there is no warranty for the free library. Also, if the library is
54
- modified by someone else and passed on, the recipients should know
55
- that what they have is not the original version, so that the original
56
- author's reputation will not be affected by problems that might be
57
- introduced by others.
58
-
59
- Finally, software patents pose a constant threat to the existence of
60
- any free program. We wish to make sure that a company cannot
61
- effectively restrict the users of a free program by obtaining a
62
- restrictive license from a patent holder. Therefore, we insist that
63
- any patent license obtained for a version of the library must be
64
- consistent with the full freedom of use specified in this license.
65
-
66
- Most GNU software, including some libraries, is covered by the
67
- ordinary GNU General Public License. This license, the GNU Lesser
68
- General Public License, applies to certain designated libraries, and
69
- is quite different from the ordinary General Public License. We use
70
- this license for certain libraries in order to permit linking those
71
- libraries into non-free programs.
72
-
73
- When a program is linked with a library, whether statically or using
74
- a shared library, the combination of the two is legally speaking a
75
- combined work, a derivative of the original library. The ordinary
76
- General Public License therefore permits such linking only if the
77
- entire combination fits its criteria of freedom. The Lesser General
78
- Public License permits more lax criteria for linking other code with
79
- the library.
80
-
81
- We call this license the "Lesser" General Public License because it
82
- does Less to protect the user's freedom than the ordinary General
83
- Public License. It also provides other free software developers Less
84
- of an advantage over competing non-free programs. These disadvantages
85
- are the reason we use the ordinary General Public License for many
86
- libraries. However, the Lesser license provides advantages in certain
87
- special circumstances.
88
-
89
- For example, on rare occasions, there may be a special need to
90
- encourage the widest possible use of a certain library, so that it becomes
91
- a de-facto standard. To achieve this, non-free programs must be
92
- allowed to use the library. A more frequent case is that a free
93
- library does the same job as widely used non-free libraries. In this
94
- case, there is little to gain by limiting the free library to free
95
- software only, so we use the Lesser General Public License.
96
-
97
- In other cases, permission to use a particular library in non-free
98
- programs enables a greater number of people to use a large body of
99
- free software. For example, permission to use the GNU C Library in
100
- non-free programs enables many more people to use the whole GNU
101
- operating system, as well as its variant, the GNU/Linux operating
102
- system.
103
-
104
- Although the Lesser General Public License is Less protective of the
105
- users' freedom, it does ensure that the user of a program that is
106
- linked with the Library has the freedom and the wherewithal to run
107
- that program using a modified version of the Library.
108
-
109
- The precise terms and conditions for copying, distribution and
110
- modification follow. Pay close attention to the difference between a
111
- "work based on the library" and a "work that uses the library". The
112
- former contains code derived from the library, whereas the latter must
113
- be combined with the library in order to run.
114
-
115
- GNU LESSER GENERAL PUBLIC LICENSE
116
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117
-
118
- 0. This License Agreement applies to any software library or other
119
- program which contains a notice placed by the copyright holder or
120
- other authorized party saying it may be distributed under the terms of
121
- this Lesser General Public License (also called "this License").
122
- Each licensee is addressed as "you".
123
-
124
- A "library" means a collection of software functions and/or data
125
- prepared so as to be conveniently linked with application programs
126
- (which use some of those functions and data) to form executables.
127
-
128
- The "Library", below, refers to any such software library or work
129
- which has been distributed under these terms. A "work based on the
130
- Library" means either the Library or any derivative work under
131
- copyright law: that is to say, a work containing the Library or a
132
- portion of it, either verbatim or with modifications and/or translated
133
- straightforwardly into another language. (Hereinafter, translation is
134
- included without limitation in the term "modification".)
135
-
136
- "Source code" for a work means the preferred form of the work for
137
- making modifications to it. For a library, complete source code means
138
- all the source code for all modules it contains, plus any associated
139
- interface definition files, plus the scripts used to control compilation
140
- and installation of the library.
141
-
142
- Activities other than copying, distribution and modification are not
143
- covered by this License; they are outside its scope. The act of
144
- running a program using the Library is not restricted, and output from
145
- such a program is covered only if its contents constitute a work based
146
- on the Library (independent of the use of the Library in a tool for
147
- writing it). Whether that is true depends on what the Library does
148
- and what the program that uses the Library does.
149
-
150
- 1. You may copy and distribute verbatim copies of the Library's
151
- complete source code as you receive it, in any medium, provided that
152
- you conspicuously and appropriately publish on each copy an
153
- appropriate copyright notice and disclaimer of warranty; keep intact
154
- all the notices that refer to this License and to the absence of any
155
- warranty; and distribute a copy of this License along with the
156
- Library.
157
-
158
- You may charge a fee for the physical act of transferring a copy,
159
- and you may at your option offer warranty protection in exchange for a
160
- fee.
161
-
162
- 2. You may modify your copy or copies of the Library or any portion
163
- of it, thus forming a work based on the Library, and copy and
164
- distribute such modifications or work under the terms of Section 1
165
- above, provided that you also meet all of these conditions:
166
-
167
- a) The modified work must itself be a software library.
168
-
169
- b) You must cause the files modified to carry prominent notices
170
- stating that you changed the files and the date of any change.
171
-
172
- c) You must cause the whole of the work to be licensed at no
173
- charge to all third parties under the terms of this License.
174
-
175
- d) If a facility in the modified Library refers to a function or a
176
- table of data to be supplied by an application program that uses
177
- the facility, other than as an argument passed when the facility
178
- is invoked, then you must make a good faith effort to ensure that,
179
- in the event an application does not supply such function or
180
- table, the facility still operates, and performs whatever part of
181
- its purpose remains meaningful.
182
-
183
- (For example, a function in a library to compute square roots has
184
- a purpose that is entirely well-defined independent of the
185
- application. Therefore, Subsection 2d requires that any
186
- application-supplied function or table used by this function must
187
- be optional: if the application does not supply it, the square
188
- root function must still compute square roots.)
189
-
190
- These requirements apply to the modified work as a whole. If
191
- identifiable sections of that work are not derived from the Library,
192
- and can be reasonably considered independent and separate works in
193
- themselves, then this License, and its terms, do not apply to those
194
- sections when you distribute them as separate works. But when you
195
- distribute the same sections as part of a whole which is a work based
196
- on the Library, the distribution of the whole must be on the terms of
197
- this License, whose permissions for other licensees extend to the
198
- entire whole, and thus to each and every part regardless of who wrote
199
- it.
200
-
201
- Thus, it is not the intent of this section to claim rights or contest
202
- your rights to work written entirely by you; rather, the intent is to
203
- exercise the right to control the distribution of derivative or
204
- collective works based on the Library.
205
-
206
- In addition, mere aggregation of another work not based on the Library
207
- with the Library (or with a work based on the Library) on a volume of
208
- a storage or distribution medium does not bring the other work under
209
- the scope of this License.
210
-
211
- 3. You may opt to apply the terms of the ordinary GNU General Public
212
- License instead of this License to a given copy of the Library. To do
213
- this, you must alter all the notices that refer to this License, so
214
- that they refer to the ordinary GNU General Public License, version 2,
215
- instead of to this License. (If a newer version than version 2 of the
216
- ordinary GNU General Public License has appeared, then you can specify
217
- that version instead if you wish.) Do not make any other change in
218
- these notices.
219
-
220
- Once this change is made in a given copy, it is irreversible for
221
- that copy, so the ordinary GNU General Public License applies to all
222
- subsequent copies and derivative works made from that copy.
223
-
224
- This option is useful when you wish to copy part of the code of
225
- the Library into a program that is not a library.
226
-
227
- 4. You may copy and distribute the Library (or a portion or
228
- derivative of it, under Section 2) in object code or executable form
229
- under the terms of Sections 1 and 2 above provided that you accompany
230
- it with the complete corresponding machine-readable source code, which
231
- must be distributed under the terms of Sections 1 and 2 above on a
232
- medium customarily used for software interchange.
233
-
234
- If distribution of object code is made by offering access to copy
235
- from a designated place, then offering equivalent access to copy the
236
- source code from the same place satisfies the requirement to
237
- distribute the source code, even though third parties are not
238
- compelled to copy the source along with the object code.
239
-
240
- 5. A program that contains no derivative of any portion of the
241
- Library, but is designed to work with the Library by being compiled or
242
- linked with it, is called a "work that uses the Library". Such a
243
- work, in isolation, is not a derivative work of the Library, and
244
- therefore falls outside the scope of this License.
245
-
246
- However, linking a "work that uses the Library" with the Library
247
- creates an executable that is a derivative of the Library (because it
248
- contains portions of the Library), rather than a "work that uses the
249
- library". The executable is therefore covered by this License.
250
- Section 6 states terms for distribution of such executables.
251
-
252
- When a "work that uses the Library" uses material from a header file
253
- that is part of the Library, the object code for the work may be a
254
- derivative work of the Library even though the source code is not.
255
- Whether this is true is especially significant if the work can be
256
- linked without the Library, or if the work is itself a library. The
257
- threshold for this to be true is not precisely defined by law.
258
-
259
- If such an object file uses only numerical parameters, data
260
- structure layouts and accessors, and small macros and small inline
261
- functions (ten lines or less in length), then the use of the object
262
- file is unrestricted, regardless of whether it is legally a derivative
263
- work. (Executables containing this object code plus portions of the
264
- Library will still fall under Section 6.)
265
-
266
- Otherwise, if the work is a derivative of the Library, you may
267
- distribute the object code for the work under the terms of Section 6.
268
- Any executables containing that work also fall under Section 6,
269
- whether or not they are linked directly with the Library itself.
270
-
271
- 6. As an exception to the Sections above, you may also combine or
272
- link a "work that uses the Library" with the Library to produce a
273
- work containing portions of the Library, and distribute that work
274
- under terms of your choice, provided that the terms permit
275
- modification of the work for the customer's own use and reverse
276
- engineering for debugging such modifications.
277
-
278
- You must give prominent notice with each copy of the work that the
279
- Library is used in it and that the Library and its use are covered by
280
- this License. You must supply a copy of this License. If the work
281
- during execution displays copyright notices, you must include the
282
- copyright notice for the Library among them, as well as a reference
283
- directing the user to the copy of this License. Also, you must do one
284
- of these things:
285
-
286
- a) Accompany the work with the complete corresponding
287
- machine-readable source code for the Library including whatever
288
- changes were used in the work (which must be distributed under
289
- Sections 1 and 2 above); and, if the work is an executable linked
290
- with the Library, with the complete machine-readable "work that
291
- uses the Library", as object code and/or source code, so that the
292
- user can modify the Library and then relink to produce a modified
293
- executable containing the modified Library. (It is understood
294
- that the user who changes the contents of definitions files in the
295
- Library will not necessarily be able to recompile the application
296
- to use the modified definitions.)
297
-
298
- b) Use a suitable shared library mechanism for linking with the
299
- Library. A suitable mechanism is one that (1) uses at run time a
300
- copy of the library already present on the user's computer system,
301
- rather than copying library functions into the executable, and (2)
302
- will operate properly with a modified version of the library, if
303
- the user installs one, as long as the modified version is
304
- interface-compatible with the version that the work was made with.
305
-
306
- c) Accompany the work with a written offer, valid for at
307
- least three years, to give the same user the materials
308
- specified in Subsection 6a, above, for a charge no more
309
- than the cost of performing this distribution.
310
-
311
- d) If distribution of the work is made by offering access to copy
312
- from a designated place, offer equivalent access to copy the above
313
- specified materials from the same place.
314
-
315
- e) Verify that the user has already received a copy of these
316
- materials or that you have already sent this user a copy.
317
-
318
- For an executable, the required form of the "work that uses the
319
- Library" must include any data and utility programs needed for
320
- reproducing the executable from it. However, as a special exception,
321
- the materials to be distributed need not include anything that is
322
- normally distributed (in either source or binary form) with the major
323
- components (compiler, kernel, and so on) of the operating system on
324
- which the executable runs, unless that component itself accompanies
325
- the executable.
326
-
327
- It may happen that this requirement contradicts the license
328
- restrictions of other proprietary libraries that do not normally
329
- accompany the operating system. Such a contradiction means you cannot
330
- use both them and the Library together in an executable that you
331
- distribute.
332
-
333
- 7. You may place library facilities that are a work based on the
334
- Library side-by-side in a single library together with other library
335
- facilities not covered by this License, and distribute such a combined
336
- library, provided that the separate distribution of the work based on
337
- the Library and of the other library facilities is otherwise
338
- permitted, and provided that you do these two things:
339
-
340
- a) Accompany the combined library with a copy of the same work
341
- based on the Library, uncombined with any other library
342
- facilities. This must be distributed under the terms of the
343
- Sections above.
344
-
345
- b) Give prominent notice with the combined library of the fact
346
- that part of it is a work based on the Library, and explaining
347
- where to find the accompanying uncombined form of the same work.
348
-
349
- 8. You may not copy, modify, sublicense, link with, or distribute
350
- the Library except as expressly provided under this License. Any
351
- attempt otherwise to copy, modify, sublicense, link with, or
352
- distribute the Library is void, and will automatically terminate your
353
- rights under this License. However, parties who have received copies,
354
- or rights, from you under this License will not have their licenses
355
- terminated so long as such parties remain in full compliance.
356
-
357
- 9. You are not required to accept this License, since you have not
358
- signed it. However, nothing else grants you permission to modify or
359
- distribute the Library or its derivative works. These actions are
360
- prohibited by law if you do not accept this License. Therefore, by
361
- modifying or distributing the Library (or any work based on the
362
- Library), you indicate your acceptance of this License to do so, and
363
- all its terms and conditions for copying, distributing or modifying
364
- the Library or works based on it.
365
-
366
- 10. Each time you redistribute the Library (or any work based on the
367
- Library), the recipient automatically receives a license from the
368
- original licensor to copy, distribute, link with or modify the Library
369
- subject to these terms and conditions. You may not impose any further
370
- restrictions on the recipients' exercise of the rights granted herein.
371
- You are not responsible for enforcing compliance by third parties with
372
- this License.
373
-
374
- 11. If, as a consequence of a court judgment or allegation of patent
375
- infringement or for any other reason (not limited to patent issues),
376
- conditions are imposed on you (whether by court order, agreement or
377
- otherwise) that contradict the conditions of this License, they do not
378
- excuse you from the conditions of this License. If you cannot
379
- distribute so as to satisfy simultaneously your obligations under this
380
- License and any other pertinent obligations, then as a consequence you
381
- may not distribute the Library at all. For example, if a patent
382
- license would not permit royalty-free redistribution of the Library by
383
- all those who receive copies directly or indirectly through you, then
384
- the only way you could satisfy both it and this License would be to
385
- refrain entirely from distribution of the Library.
386
-
387
- If any portion of this section is held invalid or unenforceable under any
388
- particular circumstance, the balance of the section is intended to apply,
389
- and the section as a whole is intended to apply in other circumstances.
390
-
391
- It is not the purpose of this section to induce you to infringe any
392
- patents or other property right claims or to contest validity of any
393
- such claims; this section has the sole purpose of protecting the
394
- integrity of the free software distribution system which is
395
- implemented by public license practices. Many people have made
396
- generous contributions to the wide range of software distributed
397
- through that system in reliance on consistent application of that
398
- system; it is up to the author/donor to decide if he or she is willing
399
- to distribute software through any other system and a licensee cannot
400
- impose that choice.
401
-
402
- This section is intended to make thoroughly clear what is believed to
403
- be a consequence of the rest of this License.
404
-
405
- 12. If the distribution and/or use of the Library is restricted in
406
- certain countries either by patents or by copyrighted interfaces, the
407
- original copyright holder who places the Library under this License may add
408
- an explicit geographical distribution limitation excluding those countries,
409
- so that distribution is permitted only in or among countries not thus
410
- excluded. In such case, this License incorporates the limitation as if
411
- written in the body of this License.
412
-
413
- 13. The Free Software Foundation may publish revised and/or new
414
- versions of the Lesser General Public License from time to time.
415
- Such new versions will be similar in spirit to the present version,
416
- but may differ in detail to address new problems or concerns.
417
-
418
- Each version is given a distinguishing version number. If the Library
419
- specifies a version number of this License which applies to it and
420
- "any later version", you have the option of following the terms and
421
- conditions either of that version or of any later version published by
422
- the Free Software Foundation. If the Library does not specify a
423
- license version number, you may choose any version ever published by
424
- the Free Software Foundation.
425
-
426
- 14. If you wish to incorporate parts of the Library into other free
427
- programs whose distribution conditions are incompatible with these,
428
- write to the author to ask for permission. For software which is
429
- copyrighted by the Free Software Foundation, write to the Free
430
- Software Foundation; we sometimes make exceptions for this. Our
431
- decision will be guided by the two goals of preserving the free status
432
- of all derivatives of our free software and of promoting the sharing
433
- and reuse of software generally.
434
-
435
- NO WARRANTY
436
-
437
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438
- WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439
- EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440
- OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441
- KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443
- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444
- LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445
- THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
-
447
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448
- WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449
- AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450
- FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451
- CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452
- LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453
- RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454
- FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455
- SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456
- DAMAGES.
457
-
458
- END OF TERMS AND CONDITIONS
459
-
460
- How to Apply These Terms to Your New Libraries
461
-
462
- If you develop a new library, and you want it to be of the greatest
463
- possible use to the public, we recommend making it free software that
464
- everyone can redistribute and change. You can do so by permitting
465
- redistribution under these terms (or, alternatively, under the terms of the
466
- ordinary General Public License).
467
-
468
- To apply these terms, attach the following notices to the library. It is
469
- safest to attach them to the start of each source file to most effectively
470
- convey the exclusion of warranty; and each file should have at least the
471
- "copyright" line and a pointer to where the full notice is found.
472
-
473
- <one line to give the library's name and a brief idea of what it does.>
474
- Copyright (C) <year> <name of author>
475
-
476
- This library is free software; you can redistribute it and/or
477
- modify it under the terms of the GNU Lesser General Public
478
- License as published by the Free Software Foundation; either
479
- version 2.1 of the License, or (at your option) any later version.
480
-
481
- This library is distributed in the hope that it will be useful,
482
- but WITHOUT ANY WARRANTY; without even the implied warranty of
483
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484
- Lesser General Public License for more details.
485
-
486
- You should have received a copy of the GNU Lesser General Public
487
- License along with this library; if not, write to the Free Software
488
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
489
-
490
- Also add information on how to contact you by electronic and paper mail.
491
-
492
- You should also get your employer (if you work as a programmer) or your
493
- school, if any, to sign a "copyright disclaimer" for the library, if
494
- necessary. Here is a sample; alter the names:
495
-
496
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
497
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
498
-
499
- <signature of Ty Coon>, 1 April 1990
500
- Ty Coon, President of Vice
501
-
502
- That's all there is to it!
503
-
504
-
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 2.1, February 1999
3
+
4
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ [This is the first released version of the Lesser GPL. It also counts
10
+ as the successor of the GNU Library Public License, version 2, hence
11
+ the version number 2.1.]
12
+
13
+ Preamble
14
+
15
+ The licenses for most software are designed to take away your
16
+ freedom to share and change it. By contrast, the GNU General Public
17
+ Licenses are intended to guarantee your freedom to share and change
18
+ free software--to make sure the software is free for all its users.
19
+
20
+ This license, the Lesser General Public License, applies to some
21
+ specially designated software packages--typically libraries--of the
22
+ Free Software Foundation and other authors who decide to use it. You
23
+ can use it too, but we suggest you first think carefully about whether
24
+ this license or the ordinary General Public License is the better
25
+ strategy to use in any particular case, based on the explanations below.
26
+
27
+ When we speak of free software, we are referring to freedom of use,
28
+ not price. Our General Public Licenses are designed to make sure that
29
+ you have the freedom to distribute copies of free software (and charge
30
+ for this service if you wish); that you receive source code or can get
31
+ it if you want it; that you can change the software and use pieces of
32
+ it in new free programs; and that you are informed that you can do
33
+ these things.
34
+
35
+ To protect your rights, we need to make restrictions that forbid
36
+ distributors to deny you these rights or to ask you to surrender these
37
+ rights. These restrictions translate to certain responsibilities for
38
+ you if you distribute copies of the library or if you modify it.
39
+
40
+ For example, if you distribute copies of the library, whether gratis
41
+ or for a fee, you must give the recipients all the rights that we gave
42
+ you. You must make sure that they, too, receive or can get the source
43
+ code. If you link other code with the library, you must provide
44
+ complete object files to the recipients, so that they can relink them
45
+ with the library after making changes to the library and recompiling
46
+ it. And you must show them these terms so they know their rights.
47
+
48
+ We protect your rights with a two-step method: (1) we copyright the
49
+ library, and (2) we offer you this license, which gives you legal
50
+ permission to copy, distribute and/or modify the library.
51
+
52
+ To protect each distributor, we want to make it very clear that
53
+ there is no warranty for the free library. Also, if the library is
54
+ modified by someone else and passed on, the recipients should know
55
+ that what they have is not the original version, so that the original
56
+ author's reputation will not be affected by problems that might be
57
+ introduced by others.
58
+
59
+ Finally, software patents pose a constant threat to the existence of
60
+ any free program. We wish to make sure that a company cannot
61
+ effectively restrict the users of a free program by obtaining a
62
+ restrictive license from a patent holder. Therefore, we insist that
63
+ any patent license obtained for a version of the library must be
64
+ consistent with the full freedom of use specified in this license.
65
+
66
+ Most GNU software, including some libraries, is covered by the
67
+ ordinary GNU General Public License. This license, the GNU Lesser
68
+ General Public License, applies to certain designated libraries, and
69
+ is quite different from the ordinary General Public License. We use
70
+ this license for certain libraries in order to permit linking those
71
+ libraries into non-free programs.
72
+
73
+ When a program is linked with a library, whether statically or using
74
+ a shared library, the combination of the two is legally speaking a
75
+ combined work, a derivative of the original library. The ordinary
76
+ General Public License therefore permits such linking only if the
77
+ entire combination fits its criteria of freedom. The Lesser General
78
+ Public License permits more lax criteria for linking other code with
79
+ the library.
80
+
81
+ We call this license the "Lesser" General Public License because it
82
+ does Less to protect the user's freedom than the ordinary General
83
+ Public License. It also provides other free software developers Less
84
+ of an advantage over competing non-free programs. These disadvantages
85
+ are the reason we use the ordinary General Public License for many
86
+ libraries. However, the Lesser license provides advantages in certain
87
+ special circumstances.
88
+
89
+ For example, on rare occasions, there may be a special need to
90
+ encourage the widest possible use of a certain library, so that it becomes
91
+ a de-facto standard. To achieve this, non-free programs must be
92
+ allowed to use the library. A more frequent case is that a free
93
+ library does the same job as widely used non-free libraries. In this
94
+ case, there is little to gain by limiting the free library to free
95
+ software only, so we use the Lesser General Public License.
96
+
97
+ In other cases, permission to use a particular library in non-free
98
+ programs enables a greater number of people to use a large body of
99
+ free software. For example, permission to use the GNU C Library in
100
+ non-free programs enables many more people to use the whole GNU
101
+ operating system, as well as its variant, the GNU/Linux operating
102
+ system.
103
+
104
+ Although the Lesser General Public License is Less protective of the
105
+ users' freedom, it does ensure that the user of a program that is
106
+ linked with the Library has the freedom and the wherewithal to run
107
+ that program using a modified version of the Library.
108
+
109
+ The precise terms and conditions for copying, distribution and
110
+ modification follow. Pay close attention to the difference between a
111
+ "work based on the library" and a "work that uses the library". The
112
+ former contains code derived from the library, whereas the latter must
113
+ be combined with the library in order to run.
114
+
115
+ GNU LESSER GENERAL PUBLIC LICENSE
116
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117
+
118
+ 0. This License Agreement applies to any software library or other
119
+ program which contains a notice placed by the copyright holder or
120
+ other authorized party saying it may be distributed under the terms of
121
+ this Lesser General Public License (also called "this License").
122
+ Each licensee is addressed as "you".
123
+
124
+ A "library" means a collection of software functions and/or data
125
+ prepared so as to be conveniently linked with application programs
126
+ (which use some of those functions and data) to form executables.
127
+
128
+ The "Library", below, refers to any such software library or work
129
+ which has been distributed under these terms. A "work based on the
130
+ Library" means either the Library or any derivative work under
131
+ copyright law: that is to say, a work containing the Library or a
132
+ portion of it, either verbatim or with modifications and/or translated
133
+ straightforwardly into another language. (Hereinafter, translation is
134
+ included without limitation in the term "modification".)
135
+
136
+ "Source code" for a work means the preferred form of the work for
137
+ making modifications to it. For a library, complete source code means
138
+ all the source code for all modules it contains, plus any associated
139
+ interface definition files, plus the scripts used to control compilation
140
+ and installation of the library.
141
+
142
+ Activities other than copying, distribution and modification are not
143
+ covered by this License; they are outside its scope. The act of
144
+ running a program using the Library is not restricted, and output from
145
+ such a program is covered only if its contents constitute a work based
146
+ on the Library (independent of the use of the Library in a tool for
147
+ writing it). Whether that is true depends on what the Library does
148
+ and what the program that uses the Library does.
149
+
150
+ 1. You may copy and distribute verbatim copies of the Library's
151
+ complete source code as you receive it, in any medium, provided that
152
+ you conspicuously and appropriately publish on each copy an
153
+ appropriate copyright notice and disclaimer of warranty; keep intact
154
+ all the notices that refer to this License and to the absence of any
155
+ warranty; and distribute a copy of this License along with the
156
+ Library.
157
+
158
+ You may charge a fee for the physical act of transferring a copy,
159
+ and you may at your option offer warranty protection in exchange for a
160
+ fee.
161
+
162
+ 2. You may modify your copy or copies of the Library or any portion
163
+ of it, thus forming a work based on the Library, and copy and
164
+ distribute such modifications or work under the terms of Section 1
165
+ above, provided that you also meet all of these conditions:
166
+
167
+ a) The modified work must itself be a software library.
168
+
169
+ b) You must cause the files modified to carry prominent notices
170
+ stating that you changed the files and the date of any change.
171
+
172
+ c) You must cause the whole of the work to be licensed at no
173
+ charge to all third parties under the terms of this License.
174
+
175
+ d) If a facility in the modified Library refers to a function or a
176
+ table of data to be supplied by an application program that uses
177
+ the facility, other than as an argument passed when the facility
178
+ is invoked, then you must make a good faith effort to ensure that,
179
+ in the event an application does not supply such function or
180
+ table, the facility still operates, and performs whatever part of
181
+ its purpose remains meaningful.
182
+
183
+ (For example, a function in a library to compute square roots has
184
+ a purpose that is entirely well-defined independent of the
185
+ application. Therefore, Subsection 2d requires that any
186
+ application-supplied function or table used by this function must
187
+ be optional: if the application does not supply it, the square
188
+ root function must still compute square roots.)
189
+
190
+ These requirements apply to the modified work as a whole. If
191
+ identifiable sections of that work are not derived from the Library,
192
+ and can be reasonably considered independent and separate works in
193
+ themselves, then this License, and its terms, do not apply to those
194
+ sections when you distribute them as separate works. But when you
195
+ distribute the same sections as part of a whole which is a work based
196
+ on the Library, the distribution of the whole must be on the terms of
197
+ this License, whose permissions for other licensees extend to the
198
+ entire whole, and thus to each and every part regardless of who wrote
199
+ it.
200
+
201
+ Thus, it is not the intent of this section to claim rights or contest
202
+ your rights to work written entirely by you; rather, the intent is to
203
+ exercise the right to control the distribution of derivative or
204
+ collective works based on the Library.
205
+
206
+ In addition, mere aggregation of another work not based on the Library
207
+ with the Library (or with a work based on the Library) on a volume of
208
+ a storage or distribution medium does not bring the other work under
209
+ the scope of this License.
210
+
211
+ 3. You may opt to apply the terms of the ordinary GNU General Public
212
+ License instead of this License to a given copy of the Library. To do
213
+ this, you must alter all the notices that refer to this License, so
214
+ that they refer to the ordinary GNU General Public License, version 2,
215
+ instead of to this License. (If a newer version than version 2 of the
216
+ ordinary GNU General Public License has appeared, then you can specify
217
+ that version instead if you wish.) Do not make any other change in
218
+ these notices.
219
+
220
+ Once this change is made in a given copy, it is irreversible for
221
+ that copy, so the ordinary GNU General Public License applies to all
222
+ subsequent copies and derivative works made from that copy.
223
+
224
+ This option is useful when you wish to copy part of the code of
225
+ the Library into a program that is not a library.
226
+
227
+ 4. You may copy and distribute the Library (or a portion or
228
+ derivative of it, under Section 2) in object code or executable form
229
+ under the terms of Sections 1 and 2 above provided that you accompany
230
+ it with the complete corresponding machine-readable source code, which
231
+ must be distributed under the terms of Sections 1 and 2 above on a
232
+ medium customarily used for software interchange.
233
+
234
+ If distribution of object code is made by offering access to copy
235
+ from a designated place, then offering equivalent access to copy the
236
+ source code from the same place satisfies the requirement to
237
+ distribute the source code, even though third parties are not
238
+ compelled to copy the source along with the object code.
239
+
240
+ 5. A program that contains no derivative of any portion of the
241
+ Library, but is designed to work with the Library by being compiled or
242
+ linked with it, is called a "work that uses the Library". Such a
243
+ work, in isolation, is not a derivative work of the Library, and
244
+ therefore falls outside the scope of this License.
245
+
246
+ However, linking a "work that uses the Library" with the Library
247
+ creates an executable that is a derivative of the Library (because it
248
+ contains portions of the Library), rather than a "work that uses the
249
+ library". The executable is therefore covered by this License.
250
+ Section 6 states terms for distribution of such executables.
251
+
252
+ When a "work that uses the Library" uses material from a header file
253
+ that is part of the Library, the object code for the work may be a
254
+ derivative work of the Library even though the source code is not.
255
+ Whether this is true is especially significant if the work can be
256
+ linked without the Library, or if the work is itself a library. The
257
+ threshold for this to be true is not precisely defined by law.
258
+
259
+ If such an object file uses only numerical parameters, data
260
+ structure layouts and accessors, and small macros and small inline
261
+ functions (ten lines or less in length), then the use of the object
262
+ file is unrestricted, regardless of whether it is legally a derivative
263
+ work. (Executables containing this object code plus portions of the
264
+ Library will still fall under Section 6.)
265
+
266
+ Otherwise, if the work is a derivative of the Library, you may
267
+ distribute the object code for the work under the terms of Section 6.
268
+ Any executables containing that work also fall under Section 6,
269
+ whether or not they are linked directly with the Library itself.
270
+
271
+ 6. As an exception to the Sections above, you may also combine or
272
+ link a "work that uses the Library" with the Library to produce a
273
+ work containing portions of the Library, and distribute that work
274
+ under terms of your choice, provided that the terms permit
275
+ modification of the work for the customer's own use and reverse
276
+ engineering for debugging such modifications.
277
+
278
+ You must give prominent notice with each copy of the work that the
279
+ Library is used in it and that the Library and its use are covered by
280
+ this License. You must supply a copy of this License. If the work
281
+ during execution displays copyright notices, you must include the
282
+ copyright notice for the Library among them, as well as a reference
283
+ directing the user to the copy of this License. Also, you must do one
284
+ of these things:
285
+
286
+ a) Accompany the work with the complete corresponding
287
+ machine-readable source code for the Library including whatever
288
+ changes were used in the work (which must be distributed under
289
+ Sections 1 and 2 above); and, if the work is an executable linked
290
+ with the Library, with the complete machine-readable "work that
291
+ uses the Library", as object code and/or source code, so that the
292
+ user can modify the Library and then relink to produce a modified
293
+ executable containing the modified Library. (It is understood
294
+ that the user who changes the contents of definitions files in the
295
+ Library will not necessarily be able to recompile the application
296
+ to use the modified definitions.)
297
+
298
+ b) Use a suitable shared library mechanism for linking with the
299
+ Library. A suitable mechanism is one that (1) uses at run time a
300
+ copy of the library already present on the user's computer system,
301
+ rather than copying library functions into the executable, and (2)
302
+ will operate properly with a modified version of the library, if
303
+ the user installs one, as long as the modified version is
304
+ interface-compatible with the version that the work was made with.
305
+
306
+ c) Accompany the work with a written offer, valid for at
307
+ least three years, to give the same user the materials
308
+ specified in Subsection 6a, above, for a charge no more
309
+ than the cost of performing this distribution.
310
+
311
+ d) If distribution of the work is made by offering access to copy
312
+ from a designated place, offer equivalent access to copy the above
313
+ specified materials from the same place.
314
+
315
+ e) Verify that the user has already received a copy of these
316
+ materials or that you have already sent this user a copy.
317
+
318
+ For an executable, the required form of the "work that uses the
319
+ Library" must include any data and utility programs needed for
320
+ reproducing the executable from it. However, as a special exception,
321
+ the materials to be distributed need not include anything that is
322
+ normally distributed (in either source or binary form) with the major
323
+ components (compiler, kernel, and so on) of the operating system on
324
+ which the executable runs, unless that component itself accompanies
325
+ the executable.
326
+
327
+ It may happen that this requirement contradicts the license
328
+ restrictions of other proprietary libraries that do not normally
329
+ accompany the operating system. Such a contradiction means you cannot
330
+ use both them and the Library together in an executable that you
331
+ distribute.
332
+
333
+ 7. You may place library facilities that are a work based on the
334
+ Library side-by-side in a single library together with other library
335
+ facilities not covered by this License, and distribute such a combined
336
+ library, provided that the separate distribution of the work based on
337
+ the Library and of the other library facilities is otherwise
338
+ permitted, and provided that you do these two things:
339
+
340
+ a) Accompany the combined library with a copy of the same work
341
+ based on the Library, uncombined with any other library
342
+ facilities. This must be distributed under the terms of the
343
+ Sections above.
344
+
345
+ b) Give prominent notice with the combined library of the fact
346
+ that part of it is a work based on the Library, and explaining
347
+ where to find the accompanying uncombined form of the same work.
348
+
349
+ 8. You may not copy, modify, sublicense, link with, or distribute
350
+ the Library except as expressly provided under this License. Any
351
+ attempt otherwise to copy, modify, sublicense, link with, or
352
+ distribute the Library is void, and will automatically terminate your
353
+ rights under this License. However, parties who have received copies,
354
+ or rights, from you under this License will not have their licenses
355
+ terminated so long as such parties remain in full compliance.
356
+
357
+ 9. You are not required to accept this License, since you have not
358
+ signed it. However, nothing else grants you permission to modify or
359
+ distribute the Library or its derivative works. These actions are
360
+ prohibited by law if you do not accept this License. Therefore, by
361
+ modifying or distributing the Library (or any work based on the
362
+ Library), you indicate your acceptance of this License to do so, and
363
+ all its terms and conditions for copying, distributing or modifying
364
+ the Library or works based on it.
365
+
366
+ 10. Each time you redistribute the Library (or any work based on the
367
+ Library), the recipient automatically receives a license from the
368
+ original licensor to copy, distribute, link with or modify the Library
369
+ subject to these terms and conditions. You may not impose any further
370
+ restrictions on the recipients' exercise of the rights granted herein.
371
+ You are not responsible for enforcing compliance by third parties with
372
+ this License.
373
+
374
+ 11. If, as a consequence of a court judgment or allegation of patent
375
+ infringement or for any other reason (not limited to patent issues),
376
+ conditions are imposed on you (whether by court order, agreement or
377
+ otherwise) that contradict the conditions of this License, they do not
378
+ excuse you from the conditions of this License. If you cannot
379
+ distribute so as to satisfy simultaneously your obligations under this
380
+ License and any other pertinent obligations, then as a consequence you
381
+ may not distribute the Library at all. For example, if a patent
382
+ license would not permit royalty-free redistribution of the Library by
383
+ all those who receive copies directly or indirectly through you, then
384
+ the only way you could satisfy both it and this License would be to
385
+ refrain entirely from distribution of the Library.
386
+
387
+ If any portion of this section is held invalid or unenforceable under any
388
+ particular circumstance, the balance of the section is intended to apply,
389
+ and the section as a whole is intended to apply in other circumstances.
390
+
391
+ It is not the purpose of this section to induce you to infringe any
392
+ patents or other property right claims or to contest validity of any
393
+ such claims; this section has the sole purpose of protecting the
394
+ integrity of the free software distribution system which is
395
+ implemented by public license practices. Many people have made
396
+ generous contributions to the wide range of software distributed
397
+ through that system in reliance on consistent application of that
398
+ system; it is up to the author/donor to decide if he or she is willing
399
+ to distribute software through any other system and a licensee cannot
400
+ impose that choice.
401
+
402
+ This section is intended to make thoroughly clear what is believed to
403
+ be a consequence of the rest of this License.
404
+
405
+ 12. If the distribution and/or use of the Library is restricted in
406
+ certain countries either by patents or by copyrighted interfaces, the
407
+ original copyright holder who places the Library under this License may add
408
+ an explicit geographical distribution limitation excluding those countries,
409
+ so that distribution is permitted only in or among countries not thus
410
+ excluded. In such case, this License incorporates the limitation as if
411
+ written in the body of this License.
412
+
413
+ 13. The Free Software Foundation may publish revised and/or new
414
+ versions of the Lesser General Public License from time to time.
415
+ Such new versions will be similar in spirit to the present version,
416
+ but may differ in detail to address new problems or concerns.
417
+
418
+ Each version is given a distinguishing version number. If the Library
419
+ specifies a version number of this License which applies to it and
420
+ "any later version", you have the option of following the terms and
421
+ conditions either of that version or of any later version published by
422
+ the Free Software Foundation. If the Library does not specify a
423
+ license version number, you may choose any version ever published by
424
+ the Free Software Foundation.
425
+
426
+ 14. If you wish to incorporate parts of the Library into other free
427
+ programs whose distribution conditions are incompatible with these,
428
+ write to the author to ask for permission. For software which is
429
+ copyrighted by the Free Software Foundation, write to the Free
430
+ Software Foundation; we sometimes make exceptions for this. Our
431
+ decision will be guided by the two goals of preserving the free status
432
+ of all derivatives of our free software and of promoting the sharing
433
+ and reuse of software generally.
434
+
435
+ NO WARRANTY
436
+
437
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438
+ WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439
+ EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440
+ OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444
+ LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445
+ THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
+
447
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449
+ AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450
+ FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452
+ LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453
+ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454
+ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455
+ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456
+ DAMAGES.
457
+
458
+ END OF TERMS AND CONDITIONS
459
+
460
+ How to Apply These Terms to Your New Libraries
461
+
462
+ If you develop a new library, and you want it to be of the greatest
463
+ possible use to the public, we recommend making it free software that
464
+ everyone can redistribute and change. You can do so by permitting
465
+ redistribution under these terms (or, alternatively, under the terms of the
466
+ ordinary General Public License).
467
+
468
+ To apply these terms, attach the following notices to the library. It is
469
+ safest to attach them to the start of each source file to most effectively
470
+ convey the exclusion of warranty; and each file should have at least the
471
+ "copyright" line and a pointer to where the full notice is found.
472
+
473
+ <one line to give the library's name and a brief idea of what it does.>
474
+ Copyright (C) <year> <name of author>
475
+
476
+ This library is free software; you can redistribute it and/or
477
+ modify it under the terms of the GNU Lesser General Public
478
+ License as published by the Free Software Foundation; either
479
+ version 2.1 of the License, or (at your option) any later version.
480
+
481
+ This library is distributed in the hope that it will be useful,
482
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
483
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484
+ Lesser General Public License for more details.
485
+
486
+ You should have received a copy of the GNU Lesser General Public
487
+ License along with this library; if not, write to the Free Software
488
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
489
+
490
+ Also add information on how to contact you by electronic and paper mail.
491
+
492
+ You should also get your employer (if you work as a programmer) or your
493
+ school, if any, to sign a "copyright disclaimer" for the library, if
494
+ necessary. Here is a sample; alter the names:
495
+
496
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
497
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
498
+
499
+ <signature of Ty Coon>, 1 April 1990
500
+ Ty Coon, President of Vice
501
+
502
+ That's all there is to it!
503
+
504
+
{libraries → classes}/PHPExcel/Shared/PCLZip/pclzip.lib.php RENAMED
@@ -1,5691 +1,5691 @@
1
- <?php
2
- // --------------------------------------------------------------------------------
3
- // PhpConcept Library - Zip Module 2.8.2
4
- // --------------------------------------------------------------------------------
5
- // License GNU/LGPL - Vincent Blavet - August 2009
6
- // http://www.phpconcept.net
7
- // --------------------------------------------------------------------------------
8
- //
9
- // Presentation :
10
- // PclZip is a PHP library that manage ZIP archives.
11
- // So far tests show that archives generated by PclZip are readable by
12
- // WinZip application and other tools.
13
- //
14
- // Description :
15
- // See readme.txt and http://www.phpconcept.net
16
- //
17
- // Warning :
18
- // This library and the associated files are non commercial, non professional
19
- // work.
20
- // It should not have unexpected results. However if any damage is caused by
21
- // this software the author can not be responsible.
22
- // The use of this software is at the risk of the user.
23
- //
24
- // --------------------------------------------------------------------------------
25
- // $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $
26
- // --------------------------------------------------------------------------------
27
-
28
- // ----- Constants
29
- if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
30
- define( 'PCLZIP_READ_BLOCK_SIZE', 2048 );
31
- }
32
-
33
- // ----- File list separator
34
- // In version 1.x of PclZip, the separator for file list is a space
35
- // (which is not a very smart choice, specifically for windows paths !).
36
- // A better separator should be a comma (,). This constant gives you the
37
- // abilty to change that.
38
- // However notice that changing this value, may have impact on existing
39
- // scripts, using space separated filenames.
40
- // Recommanded values for compatibility with older versions :
41
- //define( 'PCLZIP_SEPARATOR', ' ' );
42
- // Recommanded values for smart separation of filenames.
43
- if (!defined('PCLZIP_SEPARATOR')) {
44
- define( 'PCLZIP_SEPARATOR', ',' );
45
- }
46
-
47
- // ----- Error configuration
48
- // 0 : PclZip Class integrated error handling
49
- // 1 : PclError external library error handling. By enabling this
50
- // you must ensure that you have included PclError library.
51
- // [2,...] : reserved for futur use
52
- if (!defined('PCLZIP_ERROR_EXTERNAL')) {
53
- define( 'PCLZIP_ERROR_EXTERNAL', 0 );
54
- }
55
-
56
- // ----- Optional static temporary directory
57
- // By default temporary files are generated in the script current
58
- // path.
59
- // If defined :
60
- // - MUST BE terminated by a '/'.
61
- // - MUST be a valid, already created directory
62
- // Samples :
63
- // define( 'PCLZIP_TEMPORARY_DIR', '/temp/' );
64
- // define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' );
65
- if (!defined('PCLZIP_TEMPORARY_DIR')) {
66
- define( 'PCLZIP_TEMPORARY_DIR', '' );
67
- }
68
-
69
- // ----- Optional threshold ratio for use of temporary files
70
- // Pclzip sense the size of the file to add/extract and decide to
71
- // use or not temporary file. The algorythm is looking for
72
- // memory_limit of PHP and apply a ratio.
73
- // threshold = memory_limit * ratio.
74
- // Recommended values are under 0.5. Default 0.47.
75
- // Samples :
76
- // define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 );
77
- if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) {
78
- define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.47 );
79
- }
80
-
81
- // --------------------------------------------------------------------------------
82
- // ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****
83
- // --------------------------------------------------------------------------------
84
-
85
- // ----- Global variables
86
- $g_pclzip_version = "2.8.2";
87
-
88
- // ----- Error codes
89
- // -1 : Unable to open file in binary write mode
90
- // -2 : Unable to open file in binary read mode
91
- // -3 : Invalid parameters
92
- // -4 : File does not exist
93
- // -5 : Filename is too long (max. 255)
94
- // -6 : Not a valid zip file
95
- // -7 : Invalid extracted file size
96
- // -8 : Unable to create directory
97
- // -9 : Invalid archive extension
98
- // -10 : Invalid archive format
99
- // -11 : Unable to delete file (unlink)
100
- // -12 : Unable to rename file (rename)
101
- // -13 : Invalid header checksum
102
- // -14 : Invalid archive size
103
- define( 'PCLZIP_ERR_USER_ABORTED', 2 );
104
- define( 'PCLZIP_ERR_NO_ERROR', 0 );
105
- define( 'PCLZIP_ERR_WRITE_OPEN_FAIL', -1 );
106
- define( 'PCLZIP_ERR_READ_OPEN_FAIL', -2 );
107
- define( 'PCLZIP_ERR_INVALID_PARAMETER', -3 );
108
- define( 'PCLZIP_ERR_MISSING_FILE', -4 );
109
- define( 'PCLZIP_ERR_FILENAME_TOO_LONG', -5 );
110
- define( 'PCLZIP_ERR_INVALID_ZIP', -6 );
111
- define( 'PCLZIP_ERR_BAD_EXTRACTED_FILE', -7 );
112
- define( 'PCLZIP_ERR_DIR_CREATE_FAIL', -8 );
113
- define( 'PCLZIP_ERR_BAD_EXTENSION', -9 );
114
- define( 'PCLZIP_ERR_BAD_FORMAT', -10 );
115
- define( 'PCLZIP_ERR_DELETE_FILE_FAIL', -11 );
116
- define( 'PCLZIP_ERR_RENAME_FILE_FAIL', -12 );
117
- define( 'PCLZIP_ERR_BAD_CHECKSUM', -13 );
118
- define( 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14 );
119
- define( 'PCLZIP_ERR_MISSING_OPTION_VALUE', -15 );
120
- define( 'PCLZIP_ERR_INVALID_OPTION_VALUE', -16 );
121
- define( 'PCLZIP_ERR_ALREADY_A_DIRECTORY', -17 );
122
- define( 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18 );
123
- define( 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19 );
124
- define( 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20 );
125
- define( 'PCLZIP_ERR_DIRECTORY_RESTRICTION', -21 );
126
-
127
- // ----- Options values
128
- define( 'PCLZIP_OPT_PATH', 77001 );
129
- define( 'PCLZIP_OPT_ADD_PATH', 77002 );
130
- define( 'PCLZIP_OPT_REMOVE_PATH', 77003 );
131
- define( 'PCLZIP_OPT_REMOVE_ALL_PATH', 77004 );
132
- define( 'PCLZIP_OPT_SET_CHMOD', 77005 );
133
- define( 'PCLZIP_OPT_EXTRACT_AS_STRING', 77006 );
134
- define( 'PCLZIP_OPT_NO_COMPRESSION', 77007 );
135
- define( 'PCLZIP_OPT_BY_NAME', 77008 );
136
- define( 'PCLZIP_OPT_BY_INDEX', 77009 );
137
- define( 'PCLZIP_OPT_BY_EREG', 77010 );
138
- define( 'PCLZIP_OPT_BY_PREG', 77011 );
139
- define( 'PCLZIP_OPT_COMMENT', 77012 );
140
- define( 'PCLZIP_OPT_ADD_COMMENT', 77013 );
141
- define( 'PCLZIP_OPT_PREPEND_COMMENT', 77014 );
142
- define( 'PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015 );
143
- define( 'PCLZIP_OPT_REPLACE_NEWER', 77016 );
144
- define( 'PCLZIP_OPT_STOP_ON_ERROR', 77017 );
145
- // Having big trouble with crypt. Need to multiply 2 long int
146
- // which is not correctly supported by PHP ...
147
- //define( 'PCLZIP_OPT_CRYPT', 77018 );
148
- define( 'PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019 );
149
- define( 'PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020 );
150
- define( 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020 ); // alias
151
- define( 'PCLZIP_OPT_TEMP_FILE_ON', 77021 );
152
- define( 'PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021 ); // alias
153
- define( 'PCLZIP_OPT_TEMP_FILE_OFF', 77022 );
154
- define( 'PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022 ); // alias
155
-
156
- // ----- File description attributes
157
- define( 'PCLZIP_ATT_FILE_NAME', 79001 );
158
- define( 'PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002 );
159
- define( 'PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003 );
160
- define( 'PCLZIP_ATT_FILE_MTIME', 79004 );
161
- define( 'PCLZIP_ATT_FILE_CONTENT', 79005 );
162
- define( 'PCLZIP_ATT_FILE_COMMENT', 79006 );
163
-
164
- // ----- Call backs values
165
- define( 'PCLZIP_CB_PRE_EXTRACT', 78001 );
166
- define( 'PCLZIP_CB_POST_EXTRACT', 78002 );
167
- define( 'PCLZIP_CB_PRE_ADD', 78003 );
168
- define( 'PCLZIP_CB_POST_ADD', 78004 );
169
- /* For futur use
170
- define( 'PCLZIP_CB_PRE_LIST', 78005 );
171
- define( 'PCLZIP_CB_POST_LIST', 78006 );
172
- define( 'PCLZIP_CB_PRE_DELETE', 78007 );
173
- define( 'PCLZIP_CB_POST_DELETE', 78008 );
174
- */
175
-
176
- // --------------------------------------------------------------------------------
177
- // Class : PclZip
178
- // Description :
179
- // PclZip is the class that represent a Zip archive.
180
- // The public methods allow the manipulation of the archive.
181
- // Attributes :
182
- // Attributes must not be accessed directly.
183
- // Methods :
184
- // PclZip() : Object creator
185
- // create() : Creates the Zip archive
186
- // listContent() : List the content of the Zip archive
187
- // extract() : Extract the content of the archive
188
- // properties() : List the properties of the archive
189
- // --------------------------------------------------------------------------------
190
- class PclZip
191
- {
192
- // ----- Filename of the zip file
193
- var $zipname = '';
194
-
195
- // ----- File descriptor of the zip file
196
- var $zip_fd = 0;
197
-
198
- // ----- Internal error handling
199
- var $error_code = 1;
200
- var $error_string = '';
201
-
202
- // ----- Current status of the magic_quotes_runtime
203
- // This value store the php configuration for magic_quotes
204
- // The class can then disable the magic_quotes and reset it after
205
- var $magic_quotes_status;
206
-
207
- // --------------------------------------------------------------------------------
208
- // Function : PclZip()
209
- // Description :
210
- // Creates a PclZip object and set the name of the associated Zip archive
211
- // filename.
212
- // Note that no real action is taken, if the archive does not exist it is not
213
- // created. Use create() for that.
214
- // --------------------------------------------------------------------------------
215
- function PclZip($p_zipname)
216
- {
217
-
218
- // ----- Tests the zlib
219
- if (!function_exists('gzopen'))
220
- {
221
- die('Abort '.basename(__FILE__).' : Missing zlib extensions');
222
- }
223
-
224
- // ----- Set the attributes
225
- $this->zipname = $p_zipname;
226
- $this->zip_fd = 0;
227
- $this->magic_quotes_status = -1;
228
-
229
- // ----- Return
230
- return;
231
- }
232
- // --------------------------------------------------------------------------------
233
-
234
- // --------------------------------------------------------------------------------
235
- // Function :
236
- // create($p_filelist, $p_add_dir="", $p_remove_dir="")
237
- // create($p_filelist, $p_option, $p_option_value, ...)
238
- // Description :
239
- // This method supports two different synopsis. The first one is historical.
240
- // This method creates a Zip Archive. The Zip file is created in the
241
- // filesystem. The files and directories indicated in $p_filelist
242
- // are added in the archive. See the parameters description for the
243
- // supported format of $p_filelist.
244
- // When a directory is in the list, the directory and its content is added
245
- // in the archive.
246
- // In this synopsis, the function takes an optional variable list of
247
- // options. See bellow the supported options.
248
- // Parameters :
249
- // $p_filelist : An array containing file or directory names, or
250
- // a string containing one filename or one directory name, or
251
- // a string containing a list of filenames and/or directory
252
- // names separated by spaces.
253
- // $p_add_dir : A path to add before the real path of the archived file,
254
- // in order to have it memorized in the archive.
255
- // $p_remove_dir : A path to remove from the real path of the file to archive,
256
- // in order to have a shorter path memorized in the archive.
257
- // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
258
- // is removed first, before $p_add_dir is added.
259
- // Options :
260
- // PCLZIP_OPT_ADD_PATH :
261
- // PCLZIP_OPT_REMOVE_PATH :
262
- // PCLZIP_OPT_REMOVE_ALL_PATH :
263
- // PCLZIP_OPT_COMMENT :
264
- // PCLZIP_CB_PRE_ADD :
265
- // PCLZIP_CB_POST_ADD :
266
- // Return Values :
267
- // 0 on failure,
268
- // The list of the added files, with a status of the add action.
269
- // (see PclZip::listContent() for list entry format)
270
- // --------------------------------------------------------------------------------
271
- function create($p_filelist)
272
- {
273
- $v_result=1;
274
-
275
- // ----- Reset the error handler
276
- $this->privErrorReset();
277
-
278
- // ----- Set default values
279
- $v_options = array();
280
- $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
281
-
282
- // ----- Look for variable options arguments
283
- $v_size = func_num_args();
284
-
285
- // ----- Look for arguments
286
- if ($v_size > 1) {
287
- // ----- Get the arguments
288
- $v_arg_list = func_get_args();
289
-
290
- // ----- Remove from the options list the first argument
291
- array_shift($v_arg_list);
292
- $v_size--;
293
-
294
- // ----- Look for first arg
295
- if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
296
-
297
- // ----- Parse the options
298
- $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
299
- array (PCLZIP_OPT_REMOVE_PATH => 'optional',
300
- PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
301
- PCLZIP_OPT_ADD_PATH => 'optional',
302
- PCLZIP_CB_PRE_ADD => 'optional',
303
- PCLZIP_CB_POST_ADD => 'optional',
304
- PCLZIP_OPT_NO_COMPRESSION => 'optional',
305
- PCLZIP_OPT_COMMENT => 'optional',
306
- PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
307
- PCLZIP_OPT_TEMP_FILE_ON => 'optional',
308
- PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
309
- //, PCLZIP_OPT_CRYPT => 'optional'
310
- ));
311
- if ($v_result != 1) {
312
- return 0;
313
- }
314
- }
315
-
316
- // ----- Look for 2 args
317
- // Here we need to support the first historic synopsis of the
318
- // method.
319
- else {
320
-
321
- // ----- Get the first argument
322
- $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
323
-
324
- // ----- Look for the optional second argument
325
- if ($v_size == 2) {
326
- $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
327
- }
328
- else if ($v_size > 2) {
329
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
330
- "Invalid number / type of arguments");
331
- return 0;
332
- }
333
- }
334
- }
335
-
336
- // ----- Look for default option values
337
- $this->privOptionDefaultThreshold($v_options);
338
-
339
- // ----- Init
340
- $v_string_list = array();
341
- $v_att_list = array();
342
- $v_filedescr_list = array();
343
- $p_result_list = array();
344
-
345
- // ----- Look if the $p_filelist is really an array
346
- if (is_array($p_filelist)) {
347
-
348
- // ----- Look if the first element is also an array
349
- // This will mean that this is a file description entry
350
- if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
351
- $v_att_list = $p_filelist;
352
- }
353
-
354
- // ----- The list is a list of string names
355
- else {
356
- $v_string_list = $p_filelist;
357
- }
358
- }
359
-
360
- // ----- Look if the $p_filelist is a string
361
- else if (is_string($p_filelist)) {
362
- // ----- Create a list from the string
363
- $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
364
- }
365
-
366
- // ----- Invalid variable type for $p_filelist
367
- else {
368
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
369
- return 0;
370
- }
371
-
372
- // ----- Reformat the string list
373
- if (sizeof($v_string_list) != 0) {
374
- foreach ($v_string_list as $v_string) {
375
- if ($v_string != '') {
376
- $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
377
- }
378
- else {
379
- }
380
- }
381
- }
382
-
383
- // ----- For each file in the list check the attributes
384
- $v_supported_attributes
385
- = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
386
- ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
387
- ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
388
- ,PCLZIP_ATT_FILE_MTIME => 'optional'
389
- ,PCLZIP_ATT_FILE_CONTENT => 'optional'
390
- ,PCLZIP_ATT_FILE_COMMENT => 'optional'
391
- );
392
- foreach ($v_att_list as $v_entry) {
393
- $v_result = $this->privFileDescrParseAtt($v_entry,
394
- $v_filedescr_list[],
395
- $v_options,
396
- $v_supported_attributes);
397
- if ($v_result != 1) {
398
- return 0;
399
- }
400
- }
401
-
402
- // ----- Expand the filelist (expand directories)
403
- $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
404
- if ($v_result != 1) {
405
- return 0;
406
- }
407
-
408
- // ----- Call the create fct
409
- $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
410
- if ($v_result != 1) {
411
- return 0;
412
- }
413
-
414
- // ----- Return
415
- return $p_result_list;
416
- }
417
- // --------------------------------------------------------------------------------
418
-
419
- // --------------------------------------------------------------------------------
420
- // Function :
421
- // add($p_filelist, $p_add_dir="", $p_remove_dir="")
422
- // add($p_filelist, $p_option, $p_option_value, ...)
423
- // Description :
424
- // This method supports two synopsis. The first one is historical.
425
- // This methods add the list of files in an existing archive.
426
- // If a file with the same name already exists, it is added at the end of the
427
- // archive, the first one is still present.
428
- // If the archive does not exist, it is created.
429
- // Parameters :
430
- // $p_filelist : An array containing file or directory names, or
431
- // a string containing one filename or one directory name, or
432
- // a string containing a list of filenames and/or directory
433
- // names separated by spaces.
434
- // $p_add_dir : A path to add before the real path of the archived file,
435
- // in order to have it memorized in the archive.
436
- // $p_remove_dir : A path to remove from the real path of the file to archive,
437
- // in order to have a shorter path memorized in the archive.
438
- // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
439
- // is removed first, before $p_add_dir is added.
440
- // Options :
441
- // PCLZIP_OPT_ADD_PATH :
442
- // PCLZIP_OPT_REMOVE_PATH :
443
- // PCLZIP_OPT_REMOVE_ALL_PATH :
444
- // PCLZIP_OPT_COMMENT :
445
- // PCLZIP_OPT_ADD_COMMENT :
446
- // PCLZIP_OPT_PREPEND_COMMENT :
447
- // PCLZIP_CB_PRE_ADD :
448
- // PCLZIP_CB_POST_ADD :
449
- // Return Values :
450
- // 0 on failure,
451
- // The list of the added files, with a status of the add action.
452
- // (see PclZip::listContent() for list entry format)
453
- // --------------------------------------------------------------------------------
454
- function add($p_filelist)
455
- {
456
- $v_result=1;
457
-
458
- // ----- Reset the error handler
459
- $this->privErrorReset();
460
-
461
- // ----- Set default values
462
- $v_options = array();
463
- $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
464
-
465
- // ----- Look for variable options arguments
466
- $v_size = func_num_args();
467
-
468
- // ----- Look for arguments
469
- if ($v_size > 1) {
470
- // ----- Get the arguments
471
- $v_arg_list = func_get_args();
472
-
473
- // ----- Remove form the options list the first argument
474
- array_shift($v_arg_list);
475
- $v_size--;
476
-
477
- // ----- Look for first arg
478
- if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
479
-
480
- // ----- Parse the options
481
- $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
482
- array (PCLZIP_OPT_REMOVE_PATH => 'optional',
483
- PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
484
- PCLZIP_OPT_ADD_PATH => 'optional',
485
- PCLZIP_CB_PRE_ADD => 'optional',
486
- PCLZIP_CB_POST_ADD => 'optional',
487
- PCLZIP_OPT_NO_COMPRESSION => 'optional',
488
- PCLZIP_OPT_COMMENT => 'optional',
489
- PCLZIP_OPT_ADD_COMMENT => 'optional',
490
- PCLZIP_OPT_PREPEND_COMMENT => 'optional',
491
- PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
492
- PCLZIP_OPT_TEMP_FILE_ON => 'optional',
493
- PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
494
- //, PCLZIP_OPT_CRYPT => 'optional'
495
- ));
496
- if ($v_result != 1) {
497
- return 0;
498
- }
499
- }
500
-
501
- // ----- Look for 2 args
502
- // Here we need to support the first historic synopsis of the
503
- // method.
504
- else {
505
-
506
- // ----- Get the first argument
507
- $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
508
-
509
- // ----- Look for the optional second argument
510
- if ($v_size == 2) {
511
- $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
512
- }
513
- else if ($v_size > 2) {
514
- // ----- Error log
515
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
516
-
517
- // ----- Return
518
- return 0;
519
- }
520
- }
521
- }
522
-
523
- // ----- Look for default option values
524
- $this->privOptionDefaultThreshold($v_options);
525
-
526
- // ----- Init
527
- $v_string_list = array();
528
- $v_att_list = array();
529
- $v_filedescr_list = array();
530
- $p_result_list = array();
531
-
532
- // ----- Look if the $p_filelist is really an array
533
- if (is_array($p_filelist)) {
534
-
535
- // ----- Look if the first element is also an array
536
- // This will mean that this is a file description entry
537
- if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
538
- $v_att_list = $p_filelist;
539
- }
540
-
541
- // ----- The list is a list of string names
542
- else {
543
- $v_string_list = $p_filelist;
544
- }
545
- }
546
-
547
- // ----- Look if the $p_filelist is a string
548
- else if (is_string($p_filelist)) {
549
- // ----- Create a list from the string
550
- $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
551
- }
552
-
553
- // ----- Invalid variable type for $p_filelist
554
- else {
555
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");
556
- return 0;
557
- }
558
-
559
- // ----- Reformat the string list
560
- if (sizeof($v_string_list) != 0) {
561
- foreach ($v_string_list as $v_string) {
562
- $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
563
- }
564
- }
565
-
566
- // ----- For each file in the list check the attributes
567
- $v_supported_attributes
568
- = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
569
- ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
570
- ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
571
- ,PCLZIP_ATT_FILE_MTIME => 'optional'
572
- ,PCLZIP_ATT_FILE_CONTENT => 'optional'
573
- ,PCLZIP_ATT_FILE_COMMENT => 'optional'
574
- );
575
- foreach ($v_att_list as $v_entry) {
576
- $v_result = $this->privFileDescrParseAtt($v_entry,
577
- $v_filedescr_list[],
578
- $v_options,
579
- $v_supported_attributes);
580
- if ($v_result != 1) {
581
- return 0;
582
- }
583
- }
584
-
585
- // ----- Expand the filelist (expand directories)
586
- $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
587
- if ($v_result != 1) {
588
- return 0;
589
- }
590
-
591
- // ----- Call the create fct
592
- $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
593
- if ($v_result != 1) {
594
- return 0;
595
- }
596
-
597
- // ----- Return
598
- return $p_result_list;
599
- }
600
- // --------------------------------------------------------------------------------
601
-
602
- // --------------------------------------------------------------------------------
603
- // Function : listContent()
604
- // Description :
605
- // This public method, gives the list of the files and directories, with their
606
- // properties.
607
- // The properties of each entries in the list are (used also in other functions) :
608
- // filename : Name of the file. For a create or add action it is the filename
609
- // given by the user. For an extract function it is the filename
610
- // of the extracted file.
611
- // stored_filename : Name of the file / directory stored in the archive.
612
- // size : Size of the stored file.
613
- // compressed_size : Size of the file's data compressed in the archive
614
- // (without the headers overhead)
615
- // mtime : Last known modification date of the file (UNIX timestamp)
616
- // comment : Comment associated with the file
617
- // folder : true | false
618
- // index : index of the file in the archive
619
- // status : status of the action (depending of the action) :
620
- // Values are :
621
- // ok : OK !
622
- // filtered : the file / dir is not extracted (filtered by user)
623
- // already_a_directory : the file can not be extracted because a
624
- // directory with the same name already exists
625
- // write_protected : the file can not be extracted because a file
626
- // with the same name already exists and is
627
- // write protected
628
- // newer_exist : the file was not extracted because a newer file exists
629
- // path_creation_fail : the file is not extracted because the folder
630
- // does not exist and can not be created
631
- // write_error : the file was not extracted because there was a
632
- // error while writing the file
633
- // read_error : the file was not extracted because there was a error
634
- // while reading the file
635
- // invalid_header : the file was not extracted because of an archive
636
- // format error (bad file header)
637
- // Note that each time a method can continue operating when there
638
- // is an action error on a file, the error is only logged in the file status.
639
- // Return Values :
640
- // 0 on an unrecoverable failure,
641
- // The list of the files in the archive.
642
- // --------------------------------------------------------------------------------
643
- function listContent()
644
- {
645
- $v_result=1;
646
-
647
- // ----- Reset the error handler
648
- $this->privErrorReset();
649
-
650
- // ----- Check archive
651
- if (!$this->privCheckFormat()) {
652
- return(0);
653
- }
654
-
655
- // ----- Call the extracting fct
656
- $p_list = array();
657
- if (($v_result = $this->privList($p_list)) != 1)
658
- {
659
- unset($p_list);
660
- return(0);
661
- }
662
-
663
- // ----- Return
664
- return $p_list;
665
- }
666
- // --------------------------------------------------------------------------------
667
-
668
- // --------------------------------------------------------------------------------
669
- // Function :
670
- // extract($p_path="./", $p_remove_path="")
671
- // extract([$p_option, $p_option_value, ...])
672
- // Description :
673
- // This method supports two synopsis. The first one is historical.
674
- // This method extract all the files / directories from the archive to the
675
- // folder indicated in $p_path.
676
- // If you want to ignore the 'root' part of path of the memorized files
677
- // you can indicate this in the optional $p_remove_path parameter.
678
- // By default, if a newer file with the same name already exists, the
679
- // file is not extracted.
680
- //
681
- // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
682
- // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
683
- // at the end of the path value of PCLZIP_OPT_PATH.
684
- // Parameters :
685
- // $p_path : Path where the files and directories are to be extracted
686
- // $p_remove_path : First part ('root' part) of the memorized path
687
- // (if any similar) to remove while extracting.
688
- // Options :
689
- // PCLZIP_OPT_PATH :
690
- // PCLZIP_OPT_ADD_PATH :
691
- // PCLZIP_OPT_REMOVE_PATH :
692
- // PCLZIP_OPT_REMOVE_ALL_PATH :
693
- // PCLZIP_CB_PRE_EXTRACT :
694
- // PCLZIP_CB_POST_EXTRACT :
695
- // Return Values :
696
- // 0 or a negative value on failure,
697
- // The list of the extracted files, with a status of the action.
698
- // (see PclZip::listContent() for list entry format)
699
- // --------------------------------------------------------------------------------
700
- function extract()
701
- {
702
- $v_result=1;
703
-
704
- // ----- Reset the error handler
705
- $this->privErrorReset();
706
-
707
- // ----- Check archive
708
- if (!$this->privCheckFormat()) {
709
- return(0);
710
- }
711
-
712
- // ----- Set default values
713
- $v_options = array();
714
- // $v_path = "./";
715
- $v_path = '';
716
- $v_remove_path = "";
717
- $v_remove_all_path = false;
718
-
719
- // ----- Look for variable options arguments
720
- $v_size = func_num_args();
721
-
722
- // ----- Default values for option
723
- $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
724
-
725
- // ----- Look for arguments
726
- if ($v_size > 0) {
727
- // ----- Get the arguments
728
- $v_arg_list = func_get_args();
729
-
730
- // ----- Look for first arg
731
- if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
732
-
733
- // ----- Parse the options
734
- $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
735
- array (PCLZIP_OPT_PATH => 'optional',
736
- PCLZIP_OPT_REMOVE_PATH => 'optional',
737
- PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
738
- PCLZIP_OPT_ADD_PATH => 'optional',
739
- PCLZIP_CB_PRE_EXTRACT => 'optional',
740
- PCLZIP_CB_POST_EXTRACT => 'optional',
741
- PCLZIP_OPT_SET_CHMOD => 'optional',
742
- PCLZIP_OPT_BY_NAME => 'optional',
743
- PCLZIP_OPT_BY_EREG => 'optional',
744
- PCLZIP_OPT_BY_PREG => 'optional',
745
- PCLZIP_OPT_BY_INDEX => 'optional',
746
- PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
747
- PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
748
- PCLZIP_OPT_REPLACE_NEWER => 'optional'
749
- ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
750
- ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
751
- PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
752
- PCLZIP_OPT_TEMP_FILE_ON => 'optional',
753
- PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
754
- ));
755
- if ($v_result != 1) {
756
- return 0;
757
- }
758
-
759
- // ----- Set the arguments
760
- if (isset($v_options[PCLZIP_OPT_PATH])) {
761
- $v_path = $v_options[PCLZIP_OPT_PATH];
762
- }
763
- if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
764
- $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
765
- }
766
- if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
767
- $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
768
- }
769
- if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
770
- // ----- Check for '/' in last path char
771
- if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
772
- $v_path .= '/';
773
- }
774
- $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
775
- }
776
- }
777
-
778
- // ----- Look for 2 args
779
- // Here we need to support the first historic synopsis of the
780
- // method.
781
- else {
782
-
783
- // ----- Get the first argument
784
- $v_path = $v_arg_list[0];
785
-
786
- // ----- Look for the optional second argument
787
- if ($v_size == 2) {
788
- $v_remove_path = $v_arg_list[1];
789
- }
790
- else if ($v_size > 2) {
791
- // ----- Error log
792
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
793
-
794
- // ----- Return
795
- return 0;
796
- }
797
- }
798
- }
799
-
800
- // ----- Look for default option values
801
- $this->privOptionDefaultThreshold($v_options);
802
-
803
- // ----- Trace
804
-
805
- // ----- Call the extracting fct
806
- $p_list = array();
807
- $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path,
808
- $v_remove_all_path, $v_options);
809
- if ($v_result < 1) {
810
- unset($p_list);
811
- return(0);
812
- }
813
-
814
- // ----- Return
815
- return $p_list;
816
- }
817
- // --------------------------------------------------------------------------------
818
-
819
-
820
- // --------------------------------------------------------------------------------
821
- // Function :
822
- // extractByIndex($p_index, $p_path="./", $p_remove_path="")
823
- // extractByIndex($p_index, [$p_option, $p_option_value, ...])
824
- // Description :
825
- // This method supports two synopsis. The first one is historical.
826
- // This method is doing a partial extract of the archive.
827
- // The extracted files or folders are identified by their index in the
828
- // archive (from 0 to n).
829
- // Note that if the index identify a folder, only the folder entry is
830
- // extracted, not all the files included in the archive.
831
- // Parameters :
832
- // $p_index : A single index (integer) or a string of indexes of files to
833
- // extract. The form of the string is "0,4-6,8-12" with only numbers
834
- // and '-' for range or ',' to separate ranges. No spaces or ';'
835
- // are allowed.
836
- // $p_path : Path where the files and directories are to be extracted
837
- // $p_remove_path : First part ('root' part) of the memorized path
838
- // (if any similar) to remove while extracting.
839
- // Options :
840
- // PCLZIP_OPT_PATH :
841
- // PCLZIP_OPT_ADD_PATH :
842
- // PCLZIP_OPT_REMOVE_PATH :
843
- // PCLZIP_OPT_REMOVE_ALL_PATH :
844
- // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
845
- // not as files.
846
- // The resulting content is in a new field 'content' in the file
847
- // structure.
848
- // This option must be used alone (any other options are ignored).
849
- // PCLZIP_CB_PRE_EXTRACT :
850
- // PCLZIP_CB_POST_EXTRACT :
851
- // Return Values :
852
- // 0 on failure,
853
- // The list of the extracted files, with a status of the action.
854
- // (see PclZip::listContent() for list entry format)
855
- // --------------------------------------------------------------------------------
856
- //function extractByIndex($p_index, options...)
857
- function extractByIndex($p_index)
858
- {
859
- $v_result=1;
860
-
861
- // ----- Reset the error handler
862
- $this->privErrorReset();
863
-
864
- // ----- Check archive
865
- if (!$this->privCheckFormat()) {
866
- return(0);
867
- }
868
-
869
- // ----- Set default values
870
- $v_options = array();
871
- // $v_path = "./";
872
- $v_path = '';
873
- $v_remove_path = "";
874
- $v_remove_all_path = false;
875
-
876
- // ----- Look for variable options arguments
877
- $v_size = func_num_args();
878
-
879
- // ----- Default values for option
880
- $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
881
-
882
- // ----- Look for arguments
883
- if ($v_size > 1) {
884
- // ----- Get the arguments
885
- $v_arg_list = func_get_args();
886
-
887
- // ----- Remove form the options list the first argument
888
- array_shift($v_arg_list);
889
- $v_size--;
890
-
891
- // ----- Look for first arg
892
- if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
893
-
894
- // ----- Parse the options
895
- $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
896
- array (PCLZIP_OPT_PATH => 'optional',
897
- PCLZIP_OPT_REMOVE_PATH => 'optional',
898
- PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
899
- PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
900
- PCLZIP_OPT_ADD_PATH => 'optional',
901
- PCLZIP_CB_PRE_EXTRACT => 'optional',
902
- PCLZIP_CB_POST_EXTRACT => 'optional',
903
- PCLZIP_OPT_SET_CHMOD => 'optional',
904
- PCLZIP_OPT_REPLACE_NEWER => 'optional'
905
- ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
906
- ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
907
- PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
908
- PCLZIP_OPT_TEMP_FILE_ON => 'optional',
909
- PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
910
- ));
911
- if ($v_result != 1) {
912
- return 0;
913
- }
914
-
915
- // ----- Set the arguments
916
- if (isset($v_options[PCLZIP_OPT_PATH])) {
917
- $v_path = $v_options[PCLZIP_OPT_PATH];
918
- }
919
- if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
920
- $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
921
- }
922
- if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
923
- $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
924
- }
925
- if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
926
- // ----- Check for '/' in last path char
927
- if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
928
- $v_path .= '/';
929
- }
930
- $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
931
- }
932
- if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
933
- $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
934
- }
935
- else {
936
- }
937
- }
938
-
939
- // ----- Look for 2 args
940
- // Here we need to support the first historic synopsis of the
941
- // method.
942
- else {
943
-
944
- // ----- Get the first argument
945
- $v_path = $v_arg_list[0];
946
-
947
- // ----- Look for the optional second argument
948
- if ($v_size == 2) {
949
- $v_remove_path = $v_arg_list[1];
950
- }
951
- else if ($v_size > 2) {
952
- // ----- Error log
953
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
954
-
955
- // ----- Return
956
- return 0;
957
- }
958
- }
959
- }
960
-
961
- // ----- Trace
962
-
963
- // ----- Trick
964
- // Here I want to reuse extractByRule(), so I need to parse the $p_index
965
- // with privParseOptions()
966
- $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index);
967
- $v_options_trick = array();
968
- $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick,
969
- array (PCLZIP_OPT_BY_INDEX => 'optional' ));
970
- if ($v_result != 1) {
971
- return 0;
972
- }
973
- $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
974
-
975
- // ----- Look for default option values
976
- $this->privOptionDefaultThreshold($v_options);
977
-
978
- // ----- Call the extracting fct
979
- if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
980
- return(0);
981
- }
982
-
983
- // ----- Return
984
- return $p_list;
985
- }
986
- // --------------------------------------------------------------------------------
987
-
988
- // --------------------------------------------------------------------------------
989
- // Function :
990
- // delete([$p_option, $p_option_value, ...])
991
- // Description :
992
- // This method removes files from the archive.
993
- // If no parameters are given, then all the archive is emptied.
994
- // Parameters :
995
- // None or optional arguments.
996
- // Options :
997
- // PCLZIP_OPT_BY_INDEX :
998
- // PCLZIP_OPT_BY_NAME :
999
- // PCLZIP_OPT_BY_EREG :
1000
- // PCLZIP_OPT_BY_PREG :
1001
- // Return Values :
1002
- // 0 on failure,
1003
- // The list of the files which are still present in the archive.
1004
- // (see PclZip::listContent() for list entry format)
1005
- // --------------------------------------------------------------------------------
1006
- function delete()
1007
- {
1008
- $v_result=1;
1009
-
1010
- // ----- Reset the error handler
1011
- $this->privErrorReset();
1012
-
1013
- // ----- Check archive
1014
- if (!$this->privCheckFormat()) {
1015
- return(0);
1016
- }
1017
-
1018
- // ----- Set default values
1019
- $v_options = array();
1020
-
1021
- // ----- Look for variable options arguments
1022
- $v_size = func_num_args();
1023
-
1024
- // ----- Look for arguments
1025
- if ($v_size > 0) {
1026
- // ----- Get the arguments
1027
- $v_arg_list = func_get_args();
1028
-
1029
- // ----- Parse the options
1030
- $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
1031
- array (PCLZIP_OPT_BY_NAME => 'optional',
1032
- PCLZIP_OPT_BY_EREG => 'optional',
1033
- PCLZIP_OPT_BY_PREG => 'optional',
1034
- PCLZIP_OPT_BY_INDEX => 'optional' ));
1035
- if ($v_result != 1) {
1036
- return 0;
1037
- }
1038
- }
1039
-
1040
- // ----- Magic quotes trick
1041
- $this->privDisableMagicQuotes();
1042
-
1043
- // ----- Call the delete fct
1044
- $v_list = array();
1045
- if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
1046
- $this->privSwapBackMagicQuotes();
1047
- unset($v_list);
1048
- return(0);
1049
- }
1050
-
1051
- // ----- Magic quotes trick
1052
- $this->privSwapBackMagicQuotes();
1053
-
1054
- // ----- Return
1055
- return $v_list;
1056
- }
1057
- // --------------------------------------------------------------------------------
1058
-
1059
- // --------------------------------------------------------------------------------
1060
- // Function : deleteByIndex()
1061
- // Description :
1062
- // ***** Deprecated *****
1063
- // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
1064
- // --------------------------------------------------------------------------------
1065
- function deleteByIndex($p_index)
1066
- {
1067
-
1068
- $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
1069
-
1070
- // ----- Return
1071
- return $p_list;
1072
- }
1073
- // --------------------------------------------------------------------------------
1074
-
1075
- // --------------------------------------------------------------------------------
1076
- // Function : properties()
1077
- // Description :
1078
- // This method gives the properties of the archive.
1079
- // The properties are :
1080
- // nb : Number of files in the archive
1081
- // comment : Comment associated with the archive file
1082
- // status : not_exist, ok
1083
- // Parameters :
1084
- // None
1085
- // Return Values :
1086
- // 0 on failure,
1087
- // An array with the archive properties.
1088
- // --------------------------------------------------------------------------------
1089
- function properties()
1090
- {
1091
-
1092
- // ----- Reset the error handler
1093
- $this->privErrorReset();
1094
-
1095
- // ----- Magic quotes trick
1096
- $this->privDisableMagicQuotes();
1097
-
1098
- // ----- Check archive
1099
- if (!$this->privCheckFormat()) {
1100
- $this->privSwapBackMagicQuotes();
1101
- return(0);
1102
- }
1103
-
1104
- // ----- Default properties
1105
- $v_prop = array();
1106
- $v_prop['comment'] = '';
1107
- $v_prop['nb'] = 0;
1108
- $v_prop['status'] = 'not_exist';
1109
-
1110
- // ----- Look if file exists
1111
- if (@is_file($this->zipname))
1112
- {
1113
- // ----- Open the zip file
1114
- if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
1115
- {
1116
- $this->privSwapBackMagicQuotes();
1117
-
1118
- // ----- Error log
1119
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
1120
-
1121
- // ----- Return
1122
- return 0;
1123
- }
1124
-
1125
- // ----- Read the central directory informations
1126
- $v_central_dir = array();
1127
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
1128
- {
1129
- $this->privSwapBackMagicQuotes();
1130
- return 0;
1131
- }
1132
-
1133
- // ----- Close the zip file
1134
- $this->privCloseFd();
1135
-
1136
- // ----- Set the user attributes
1137
- $v_prop['comment'] = $v_central_dir['comment'];
1138
- $v_prop['nb'] = $v_central_dir['entries'];
1139
- $v_prop['status'] = 'ok';
1140
- }
1141
-
1142
- // ----- Magic quotes trick
1143
- $this->privSwapBackMagicQuotes();
1144
-
1145
- // ----- Return
1146
- return $v_prop;
1147
- }
1148
- // --------------------------------------------------------------------------------
1149
-
1150
- // --------------------------------------------------------------------------------
1151
- // Function : duplicate()
1152
- // Description :
1153
- // This method creates an archive by copying the content of an other one. If
1154
- // the archive already exist, it is replaced by the new one without any warning.
1155
- // Parameters :
1156
- // $p_archive : The filename of a valid archive, or
1157
- // a valid PclZip object.
1158
- // Return Values :
1159
- // 1 on success.
1160
- // 0 or a negative value on error (error code).
1161
- // --------------------------------------------------------------------------------
1162
- function duplicate($p_archive)
1163
- {
1164
- $v_result = 1;
1165
-
1166
- // ----- Reset the error handler
1167
- $this->privErrorReset();
1168
-
1169
- // ----- Look if the $p_archive is a PclZip object
1170
- if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip'))
1171
- {
1172
-
1173
- // ----- Duplicate the archive
1174
- $v_result = $this->privDuplicate($p_archive->zipname);
1175
- }
1176
-
1177
- // ----- Look if the $p_archive is a string (so a filename)
1178
- else if (is_string($p_archive))
1179
- {
1180
-
1181
- // ----- Check that $p_archive is a valid zip file
1182
- // TBC : Should also check the archive format
1183
- if (!is_file($p_archive)) {
1184
- // ----- Error log
1185
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
1186
- $v_result = PCLZIP_ERR_MISSING_FILE;
1187
- }
1188
- else {
1189
- // ----- Duplicate the archive
1190
- $v_result = $this->privDuplicate($p_archive);
1191
- }
1192
- }
1193
-
1194
- // ----- Invalid variable
1195
- else
1196
- {
1197
- // ----- Error log
1198
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
1199
- $v_result = PCLZIP_ERR_INVALID_PARAMETER;
1200
- }
1201
-
1202
- // ----- Return
1203
- return $v_result;
1204
- }
1205
- // --------------------------------------------------------------------------------
1206
-
1207
- // --------------------------------------------------------------------------------
1208
- // Function : merge()
1209
- // Description :
1210
- // This method merge the $p_archive_to_add archive at the end of the current
1211
- // one ($this).
1212
- // If the archive ($this) does not exist, the merge becomes a duplicate.
1213
- // If the $p_archive_to_add archive does not exist, the merge is a success.
1214
- // Parameters :
1215
- // $p_archive_to_add : It can be directly the filename of a valid zip archive,
1216
- // or a PclZip object archive.
1217
- // Return Values :
1218
- // 1 on success,
1219
- // 0 or negative values on error (see below).
1220
- // --------------------------------------------------------------------------------
1221
- function merge($p_archive_to_add)
1222
- {
1223
- $v_result = 1;
1224
-
1225
- // ----- Reset the error handler
1226
- $this->privErrorReset();
1227
-
1228
- // ----- Check archive
1229
- if (!$this->privCheckFormat()) {
1230
- return(0);
1231
- }
1232
-
1233
- // ----- Look if the $p_archive_to_add is a PclZip object
1234
- if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip'))
1235
- {
1236
-
1237
- // ----- Merge the archive
1238
- $v_result = $this->privMerge($p_archive_to_add);
1239
- }
1240
-
1241
- // ----- Look if the $p_archive_to_add is a string (so a filename)
1242
- else if (is_string($p_archive_to_add))
1243
- {
1244
-
1245
- // ----- Create a temporary archive
1246
- $v_object_archive = new PclZip($p_archive_to_add);
1247
-
1248
- // ----- Merge the archive
1249
- $v_result = $this->privMerge($v_object_archive);
1250
- }
1251
-
1252
- // ----- Invalid variable
1253
- else
1254
- {
1255
- // ----- Error log
1256
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
1257
- $v_result = PCLZIP_ERR_INVALID_PARAMETER;
1258
- }
1259
-
1260
- // ----- Return
1261
- return $v_result;
1262
- }
1263
- // --------------------------------------------------------------------------------
1264
-
1265
-
1266
-
1267
- // --------------------------------------------------------------------------------
1268
- // Function : errorCode()
1269
- // Description :
1270
- // Parameters :
1271
- // --------------------------------------------------------------------------------
1272
- function errorCode()
1273
- {
1274
- if (PCLZIP_ERROR_EXTERNAL == 1) {
1275
- return(PclErrorCode());
1276
- }
1277
- else {
1278
- return($this->error_code);
1279
- }
1280
- }
1281
- // --------------------------------------------------------------------------------
1282
-
1283
- // --------------------------------------------------------------------------------
1284
- // Function : errorName()
1285
- // Description :
1286
- // Parameters :
1287
- // --------------------------------------------------------------------------------
1288
- function errorName($p_with_code=false)
1289
- {
1290
- $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
1291
- PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
1292
- PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
1293
- PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
1294
- PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
1295
- PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
1296
- PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
1297
- PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
1298
- PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
1299
- PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
1300
- PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
1301
- PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
1302
- PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
1303
- PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
1304
- PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
1305
- PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
1306
- PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
1307
- PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
1308
- PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION'
1309
- ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE'
1310
- ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'
1311
- );
1312
-
1313
- if (isset($v_name[$this->error_code])) {
1314
- $v_value = $v_name[$this->error_code];
1315
- }
1316
- else {
1317
- $v_value = 'NoName';
1318
- }
1319
-
1320
- if ($p_with_code) {
1321
- return($v_value.' ('.$this->error_code.')');
1322
- }
1323
- else {
1324
- return($v_value);
1325
- }
1326
- }
1327
- // --------------------------------------------------------------------------------
1328
-
1329
- // --------------------------------------------------------------------------------
1330
- // Function : errorInfo()
1331
- // Description :
1332
- // Parameters :
1333
- // --------------------------------------------------------------------------------
1334
- function errorInfo($p_full=false)
1335
- {
1336
- if (PCLZIP_ERROR_EXTERNAL == 1) {
1337
- return(PclErrorString());
1338
- }
1339
- else {
1340
- if ($p_full) {
1341
- return($this->errorName(true)." : ".$this->error_string);
1342
- }
1343
- else {
1344
- return($this->error_string." [code ".$this->error_code."]");
1345
- }
1346
- }
1347
- }
1348
- // --------------------------------------------------------------------------------
1349
-
1350
-
1351
- // --------------------------------------------------------------------------------
1352
- // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
1353
- // ***** *****
1354
- // ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY *****
1355
- // --------------------------------------------------------------------------------
1356
-
1357
-
1358
-
1359
- // --------------------------------------------------------------------------------
1360
- // Function : privCheckFormat()
1361
- // Description :
1362
- // This method check that the archive exists and is a valid zip archive.
1363
- // Several level of check exists. (futur)
1364
- // Parameters :
1365
- // $p_level : Level of check. Default 0.
1366
- // 0 : Check the first bytes (magic codes) (default value))
1367
- // 1 : 0 + Check the central directory (futur)
1368
- // 2 : 1 + Check each file header (futur)
1369
- // Return Values :
1370
- // true on success,
1371
- // false on error, the error code is set.
1372
- // --------------------------------------------------------------------------------
1373
- function privCheckFormat($p_level=0)
1374
- {
1375
- $v_result = true;
1376
-
1377
- // ----- Reset the file system cache
1378
- clearstatcache();
1379
-
1380
- // ----- Reset the error handler
1381
- $this->privErrorReset();
1382
-
1383
- // ----- Look if the file exits
1384
- if (!is_file($this->zipname)) {
1385
- // ----- Error log
1386
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");
1387
- return(false);
1388
- }
1389
-
1390
- // ----- Check that the file is readeable
1391
- if (!is_readable($this->zipname)) {
1392
- // ----- Error log
1393
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");
1394
- return(false);
1395
- }
1396
-
1397
- // ----- Check the magic code
1398
- // TBC
1399
-
1400
- // ----- Check the central header
1401
- // TBC
1402
-
1403
- // ----- Check each file header
1404
- // TBC
1405
-
1406
- // ----- Return
1407
- return $v_result;
1408
- }
1409
- // --------------------------------------------------------------------------------
1410
-
1411
- // --------------------------------------------------------------------------------
1412
- // Function : privParseOptions()
1413
- // Description :
1414
- // This internal methods reads the variable list of arguments ($p_options_list,
1415
- // $p_size) and generate an array with the options and values ($v_result_list).
1416
- // $v_requested_options contains the options that can be present and those that
1417
- // must be present.
1418
- // $v_requested_options is an array, with the option value as key, and 'optional',
1419
- // or 'mandatory' as value.
1420
- // Parameters :
1421
- // See above.
1422
- // Return Values :
1423
- // 1 on success.
1424
- // 0 on failure.
1425
- // --------------------------------------------------------------------------------
1426
- function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false)
1427
- {
1428
- $v_result=1;
1429
-
1430
- // ----- Read the options
1431
- $i=0;
1432
- while ($i<$p_size) {
1433
-
1434
- // ----- Check if the option is supported
1435
- if (!isset($v_requested_options[$p_options_list[$i]])) {
1436
- // ----- Error log
1437
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");
1438
-
1439
- // ----- Return
1440
- return PclZip::errorCode();
1441
- }
1442
-
1443
- // ----- Look for next option
1444
- switch ($p_options_list[$i]) {
1445
- // ----- Look for options that request a path value
1446
- case PCLZIP_OPT_PATH :
1447
- case PCLZIP_OPT_REMOVE_PATH :
1448
- case PCLZIP_OPT_ADD_PATH :
1449
- // ----- Check the number of parameters
1450
- if (($i+1) >= $p_size) {
1451
- // ----- Error log
1452
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1453
-
1454
- // ----- Return
1455
- return PclZip::errorCode();
1456
- }
1457
-
1458
- // ----- Get the value
1459
- $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
1460
- $i++;
1461
- break;
1462
-
1463
- case PCLZIP_OPT_TEMP_FILE_THRESHOLD :
1464
- // ----- Check the number of parameters
1465
- if (($i+1) >= $p_size) {
1466
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1467
- return PclZip::errorCode();
1468
- }
1469
-
1470
- // ----- Check for incompatible options
1471
- if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
1472
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
1473
- return PclZip::errorCode();
1474
- }
1475
-
1476
- // ----- Check the value
1477
- $v_value = $p_options_list[$i+1];
1478
- if ((!is_integer($v_value)) || ($v_value<0)) {
1479
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1480
- return PclZip::errorCode();
1481
- }
1482
-
1483
- // ----- Get the value (and convert it in bytes)
1484
- $v_result_list[$p_options_list[$i]] = $v_value*1048576;
1485
- $i++;
1486
- break;
1487
-
1488
- case PCLZIP_OPT_TEMP_FILE_ON :
1489
- // ----- Check for incompatible options
1490
- if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
1491
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
1492
- return PclZip::errorCode();
1493
- }
1494
-
1495
- $v_result_list[$p_options_list[$i]] = true;
1496
- break;
1497
-
1498
- case PCLZIP_OPT_TEMP_FILE_OFF :
1499
- // ----- Check for incompatible options
1500
- if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
1501
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
1502
- return PclZip::errorCode();
1503
- }
1504
- // ----- Check for incompatible options
1505
- if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
1506
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
1507
- return PclZip::errorCode();
1508
- }
1509
-
1510
- $v_result_list[$p_options_list[$i]] = true;
1511
- break;
1512
-
1513
- case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION :
1514
- // ----- Check the number of parameters
1515
- if (($i+1) >= $p_size) {
1516
- // ----- Error log
1517
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1518
-
1519
- // ----- Return
1520
- return PclZip::errorCode();
1521
- }
1522
-
1523
- // ----- Get the value
1524
- if ( is_string($p_options_list[$i+1])
1525
- && ($p_options_list[$i+1] != '')) {
1526
- $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
1527
- $i++;
1528
- }
1529
- else {
1530
- }
1531
- break;
1532
-
1533
- // ----- Look for options that request an array of string for value
1534
- case PCLZIP_OPT_BY_NAME :
1535
- // ----- Check the number of parameters
1536
- if (($i+1) >= $p_size) {
1537
- // ----- Error log
1538
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1539
-
1540
- // ----- Return
1541
- return PclZip::errorCode();
1542
- }
1543
-
1544
- // ----- Get the value
1545
- if (is_string($p_options_list[$i+1])) {
1546
- $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1];
1547
- }
1548
- else if (is_array($p_options_list[$i+1])) {
1549
- $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1550
- }
1551
- else {
1552
- // ----- Error log
1553
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1554
-
1555
- // ----- Return
1556
- return PclZip::errorCode();
1557
- }
1558
- $i++;
1559
- break;
1560
-
1561
- // ----- Look for options that request an EREG or PREG expression
1562
- case PCLZIP_OPT_BY_EREG :
1563
- // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
1564
- // to PCLZIP_OPT_BY_PREG
1565
- $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
1566
- case PCLZIP_OPT_BY_PREG :
1567
- //case PCLZIP_OPT_CRYPT :
1568
- // ----- Check the number of parameters
1569
- if (($i+1) >= $p_size) {
1570
- // ----- Error log
1571
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1572
-
1573
- // ----- Return
1574
- return PclZip::errorCode();
1575
- }
1576
-
1577
- // ----- Get the value
1578
- if (is_string($p_options_list[$i+1])) {
1579
- $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1580
- }
1581
- else {
1582
- // ----- Error log
1583
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1584
-
1585
- // ----- Return
1586
- return PclZip::errorCode();
1587
- }
1588
- $i++;
1589
- break;
1590
-
1591
- // ----- Look for options that takes a string
1592
- case PCLZIP_OPT_COMMENT :
1593
- case PCLZIP_OPT_ADD_COMMENT :
1594
- case PCLZIP_OPT_PREPEND_COMMENT :
1595
- // ----- Check the number of parameters
1596
- if (($i+1) >= $p_size) {
1597
- // ----- Error log
1598
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1599
- "Missing parameter value for option '"
1600
- .PclZipUtilOptionText($p_options_list[$i])
1601
- ."'");
1602
-
1603
- // ----- Return
1604
- return PclZip::errorCode();
1605
- }
1606
-
1607
- // ----- Get the value
1608
- if (is_string($p_options_list[$i+1])) {
1609
- $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1610
- }
1611
- else {
1612
- // ----- Error log
1613
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
1614
- "Wrong parameter value for option '"
1615
- .PclZipUtilOptionText($p_options_list[$i])
1616
- ."'");
1617
-
1618
- // ----- Return
1619
- return PclZip::errorCode();
1620
- }
1621
- $i++;
1622
- break;
1623
-
1624
- // ----- Look for options that request an array of index
1625
- case PCLZIP_OPT_BY_INDEX :
1626
- // ----- Check the number of parameters
1627
- if (($i+1) >= $p_size) {
1628
- // ----- Error log
1629
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1630
-
1631
- // ----- Return
1632
- return PclZip::errorCode();
1633
- }
1634
-
1635
- // ----- Get the value
1636
- $v_work_list = array();
1637
- if (is_string($p_options_list[$i+1])) {
1638
-
1639
- // ----- Remove spaces
1640
- $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', '');
1641
-
1642
- // ----- Parse items
1643
- $v_work_list = explode(",", $p_options_list[$i+1]);
1644
- }
1645
- else if (is_integer($p_options_list[$i+1])) {
1646
- $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1];
1647
- }
1648
- else if (is_array($p_options_list[$i+1])) {
1649
- $v_work_list = $p_options_list[$i+1];
1650
- }
1651
- else {
1652
- // ----- Error log
1653
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1654
-
1655
- // ----- Return
1656
- return PclZip::errorCode();
1657
- }
1658
-
1659
- // ----- Reduce the index list
1660
- // each index item in the list must be a couple with a start and
1661
- // an end value : [0,3], [5-5], [8-10], ...
1662
- // ----- Check the format of each item
1663
- $v_sort_flag=false;
1664
- $v_sort_value=0;
1665
- for ($j=0; $j<sizeof($v_work_list); $j++) {
1666
- // ----- Explode the item
1667
- $v_item_list = explode("-", $v_work_list[$j]);
1668
- $v_size_item_list = sizeof($v_item_list);
1669
-
1670
- // ----- TBC : Here we might check that each item is a
1671
- // real integer ...
1672
-
1673
- // ----- Look for single value
1674
- if ($v_size_item_list == 1) {
1675
- // ----- Set the option value
1676
- $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
1677
- $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0];
1678
- }
1679
- elseif ($v_size_item_list == 2) {
1680
- // ----- Set the option value
1681
- $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
1682
- $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1];
1683
- }
1684
- else {
1685
- // ----- Error log
1686
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1687
-
1688
- // ----- Return
1689
- return PclZip::errorCode();
1690
- }
1691
-
1692
-
1693
- // ----- Look for list sort
1694
- if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {
1695
- $v_sort_flag=true;
1696
-
1697
- // ----- TBC : An automatic sort should be writen ...
1698
- // ----- Error log
1699
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1700
-
1701
- // ----- Return
1702
- return PclZip::errorCode();
1703
- }
1704
- $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];
1705
- }
1706
-
1707
- // ----- Sort the items
1708
- if ($v_sort_flag) {
1709
- // TBC : To Be Completed
1710
- }
1711
-
1712
- // ----- Next option
1713
- $i++;
1714
- break;
1715
-
1716
- // ----- Look for options that request no value
1717
- case PCLZIP_OPT_REMOVE_ALL_PATH :
1718
- case PCLZIP_OPT_EXTRACT_AS_STRING :
1719
- case PCLZIP_OPT_NO_COMPRESSION :
1720
- case PCLZIP_OPT_EXTRACT_IN_OUTPUT :
1721
- case PCLZIP_OPT_REPLACE_NEWER :
1722
- case PCLZIP_OPT_STOP_ON_ERROR :
1723
- $v_result_list[$p_options_list[$i]] = true;
1724
- break;
1725
-
1726
- // ----- Look for options that request an octal value
1727
- case PCLZIP_OPT_SET_CHMOD :
1728
- // ----- Check the number of parameters
1729
- if (($i+1) >= $p_size) {
1730
- // ----- Error log
1731
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1732
-
1733
- // ----- Return
1734
- return PclZip::errorCode();
1735
- }
1736
-
1737
- // ----- Get the value
1738
- $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1739
- $i++;
1740
- break;
1741
-
1742
- // ----- Look for options that request a call-back
1743
- case PCLZIP_CB_PRE_EXTRACT :
1744
- case PCLZIP_CB_POST_EXTRACT :
1745
- case PCLZIP_CB_PRE_ADD :
1746
- case PCLZIP_CB_POST_ADD :
1747
- /* for futur use
1748
- case PCLZIP_CB_PRE_DELETE :
1749
- case PCLZIP_CB_POST_DELETE :
1750
- case PCLZIP_CB_PRE_LIST :
1751
- case PCLZIP_CB_POST_LIST :
1752
- */
1753
- // ----- Check the number of parameters
1754
- if (($i+1) >= $p_size) {
1755
- // ----- Error log
1756
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1757
-
1758
- // ----- Return
1759
- return PclZip::errorCode();
1760
- }
1761
-
1762
- // ----- Get the value
1763
- $v_function_name = $p_options_list[$i+1];
1764
-
1765
- // ----- Check that the value is a valid existing function
1766
- if (!function_exists($v_function_name)) {
1767
- // ----- Error log
1768
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1769
-
1770
- // ----- Return
1771
- return PclZip::errorCode();
1772
- }
1773
-
1774
- // ----- Set the attribute
1775
- $v_result_list[$p_options_list[$i]] = $v_function_name;
1776
- $i++;
1777
- break;
1778
-
1779
- default :
1780
- // ----- Error log
1781
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1782
- "Unknown parameter '"
1783
- .$p_options_list[$i]."'");
1784
-
1785
- // ----- Return
1786
- return PclZip::errorCode();
1787
- }
1788
-
1789
- // ----- Next options
1790
- $i++;
1791
- }
1792
-
1793
- // ----- Look for mandatory options
1794
- if ($v_requested_options !== false) {
1795
- for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
1796
- // ----- Look for mandatory option
1797
- if ($v_requested_options[$key] == 'mandatory') {
1798
- // ----- Look if present
1799
- if (!isset($v_result_list[$key])) {
1800
- // ----- Error log
1801
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
1802
-
1803
- // ----- Return
1804
- return PclZip::errorCode();
1805
- }
1806
- }
1807
- }
1808
- }
1809
-
1810
- // ----- Look for default values
1811
- if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
1812
-
1813
- }
1814
-
1815
- // ----- Return
1816
- return $v_result;
1817
- }
1818
- // --------------------------------------------------------------------------------
1819
-
1820
- // --------------------------------------------------------------------------------
1821
- // Function : privOptionDefaultThreshold()
1822
- // Description :
1823
- // Parameters :
1824
- // Return Values :
1825
- // --------------------------------------------------------------------------------
1826
- function privOptionDefaultThreshold(&$p_options)
1827
- {
1828
- $v_result=1;
1829
-
1830
- if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
1831
- || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {
1832
- return $v_result;
1833
- }
1834
-
1835
- // ----- Get 'memory_limit' configuration value
1836
- $v_memory_limit = ini_get('memory_limit');
1837
- $v_memory_limit = trim($v_memory_limit);
1838
- $last = strtolower(substr($v_memory_limit, -1));
1839
-
1840
- if($last == 'g')
1841
- //$v_memory_limit = $v_memory_limit*1024*1024*1024;
1842
- $v_memory_limit = $v_memory_limit*1073741824;
1843
- if($last == 'm')
1844
- //$v_memory_limit = $v_memory_limit*1024*1024;
1845
- $v_memory_limit = $v_memory_limit*1048576;
1846
- if($last == 'k')
1847
- $v_memory_limit = $v_memory_limit*1024;
1848
-
1849
- $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO);
1850
-
1851
-
1852
- // ----- Sanity check : No threshold if value lower than 1M
1853
- if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
1854
- unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
1855
- }
1856
-
1857
- // ----- Return
1858
- return $v_result;
1859
- }
1860
- // --------------------------------------------------------------------------------
1861
-
1862
- // --------------------------------------------------------------------------------
1863
- // Function : privFileDescrParseAtt()
1864
- // Description :
1865
- // Parameters :
1866
- // Return Values :
1867
- // 1 on success.
1868
- // 0 on failure.
1869
- // --------------------------------------------------------------------------------
1870
- function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false)
1871
- {
1872
- $v_result=1;
1873
-
1874
- // ----- For each file in the list check the attributes
1875
- foreach ($p_file_list as $v_key => $v_value) {
1876
-
1877
- // ----- Check if the option is supported
1878
- if (!isset($v_requested_options[$v_key])) {
1879
- // ----- Error log
1880
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file");
1881
-
1882
- // ----- Return
1883
- return PclZip::errorCode();
1884
- }
1885
-
1886
- // ----- Look for attribute
1887
- switch ($v_key) {
1888
- case PCLZIP_ATT_FILE_NAME :
1889
- if (!is_string($v_value)) {
1890
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1891
- return PclZip::errorCode();
1892
- }
1893
-
1894
- $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
1895
-
1896
- if ($p_filedescr['filename'] == '') {
1897
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'");
1898
- return PclZip::errorCode();
1899
- }
1900
-
1901
- break;
1902
-
1903
- case PCLZIP_ATT_FILE_NEW_SHORT_NAME :
1904
- if (!is_string($v_value)) {
1905
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1906
- return PclZip::errorCode();
1907
- }
1908
-
1909
- $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
1910
-
1911
- if ($p_filedescr['new_short_name'] == '') {
1912
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'");
1913
- return PclZip::errorCode();
1914
- }
1915
- break;
1916
-
1917
- case PCLZIP_ATT_FILE_NEW_FULL_NAME :
1918
- if (!is_string($v_value)) {
1919
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1920
- return PclZip::errorCode();
1921
- }
1922
-
1923
- $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
1924
-
1925
- if ($p_filedescr['new_full_name'] == '') {
1926
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'");
1927
- return PclZip::errorCode();
1928
- }
1929
- break;
1930
-
1931
- // ----- Look for options that takes a string
1932
- case PCLZIP_ATT_FILE_COMMENT :
1933
- if (!is_string($v_value)) {
1934
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1935
- return PclZip::errorCode();
1936
- }
1937
-
1938
- $p_filedescr['comment'] = $v_value;
1939
- break;
1940
-
1941
- case PCLZIP_ATT_FILE_MTIME :
1942
- if (!is_integer($v_value)) {
1943
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'");
1944
- return PclZip::errorCode();
1945
- }
1946
-
1947
- $p_filedescr['mtime'] = $v_value;
1948
- break;
1949
-
1950
- case PCLZIP_ATT_FILE_CONTENT :
1951
- $p_filedescr['content'] = $v_value;
1952
- break;
1953
-
1954
- default :
1955
- // ----- Error log
1956
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1957
- "Unknown parameter '".$v_key."'");
1958
-
1959
- // ----- Return
1960
- return PclZip::errorCode();
1961
- }
1962
-
1963
- // ----- Look for mandatory options
1964
- if ($v_requested_options !== false) {
1965
- for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
1966
- // ----- Look for mandatory option
1967
- if ($v_requested_options[$key] == 'mandatory') {
1968
- // ----- Look if present
1969
- if (!isset($p_file_list[$key])) {
1970
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
1971
- return PclZip::errorCode();
1972
- }
1973
- }
1974
- }
1975
- }
1976
-
1977
- // end foreach
1978
- }
1979
-
1980
- // ----- Return
1981
- return $v_result;
1982
- }
1983
- // --------------------------------------------------------------------------------
1984
-
1985
- // --------------------------------------------------------------------------------
1986
- // Function : privFileDescrExpand()
1987
- // Description :
1988
- // This method look for each item of the list to see if its a file, a folder
1989
- // or a string to be added as file. For any other type of files (link, other)
1990
- // just ignore the item.
1991
- // Then prepare the information that will be stored for that file.
1992
- // When its a folder, expand the folder with all the files that are in that
1993
- // folder (recursively).
1994
- // Parameters :
1995
- // Return Values :
1996
- // 1 on success.
1997
- // 0 on failure.
1998
- // --------------------------------------------------------------------------------
1999
- function privFileDescrExpand(&$p_filedescr_list, &$p_options)
2000
- {
2001
- $v_result=1;
2002
-
2003
- // ----- Create a result list
2004
- $v_result_list = array();
2005
-
2006
- // ----- Look each entry
2007
- for ($i=0; $i<sizeof($p_filedescr_list); $i++) {
2008
-
2009
- // ----- Get filedescr
2010
- $v_descr = $p_filedescr_list[$i];
2011
-
2012
- // ----- Reduce the filename
2013
- $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);
2014
- $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);
2015
-
2016
- // ----- Look for real file or folder
2017
- if (file_exists($v_descr['filename'])) {
2018
- if (@is_file($v_descr['filename'])) {
2019
- $v_descr['type'] = 'file';
2020
- }
2021
- else if (@is_dir($v_descr['filename'])) {
2022
- $v_descr['type'] = 'folder';
2023
- }
2024
- else if (@is_link($v_descr['filename'])) {
2025
- // skip
2026
- continue;
2027
- }
2028
- else {
2029
- // skip
2030
- continue;
2031
- }
2032
- }
2033
-
2034
- // ----- Look for string added as file
2035
- else if (isset($v_descr['content'])) {
2036
- $v_descr['type'] = 'virtual_file';
2037
- }
2038
-
2039
- // ----- Missing file
2040
- else {
2041
- // ----- Error log
2042
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$v_descr['filename']."' does not exist");
2043
-
2044
- // ----- Return
2045
- return PclZip::errorCode();
2046
- }
2047
-
2048
- // ----- Calculate the stored filename
2049
- $this->privCalculateStoredFilename($v_descr, $p_options);
2050
-
2051
- // ----- Add the descriptor in result list
2052
- $v_result_list[sizeof($v_result_list)] = $v_descr;
2053
-
2054
- // ----- Look for folder
2055
- if ($v_descr['type'] == 'folder') {
2056
- // ----- List of items in folder
2057
- $v_dirlist_descr = array();
2058
- $v_dirlist_nb = 0;
2059
- if ($v_folder_handler = @opendir($v_descr['filename'])) {
2060
- while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
2061
-
2062
- // ----- Skip '.' and '..'
2063
- if (($v_item_handler == '.') || ($v_item_handler == '..')) {
2064
- continue;
2065
- }
2066
-
2067
- // ----- Compose the full filename
2068
- $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler;
2069
-
2070
- // ----- Look for different stored filename
2071
- // Because the name of the folder was changed, the name of the
2072
- // files/sub-folders also change
2073
- if (($v_descr['stored_filename'] != $v_descr['filename'])
2074
- && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
2075
- if ($v_descr['stored_filename'] != '') {
2076
- $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler;
2077
- }
2078
- else {
2079
- $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
2080
- }
2081
- }
2082
-
2083
- $v_dirlist_nb++;
2084
- }
2085
-
2086
- @closedir($v_folder_handler);
2087
- }
2088
- else {
2089
- // TBC : unable to open folder in read mode
2090
- }
2091
-
2092
- // ----- Expand each element of the list
2093
- if ($v_dirlist_nb != 0) {
2094
- // ----- Expand
2095
- if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
2096
- return $v_result;
2097
- }
2098
-
2099
- // ----- Concat the resulting list
2100
- $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
2101
- }
2102
- else {
2103
- }
2104
-
2105
- // ----- Free local array
2106
- unset($v_dirlist_descr);
2107
- }
2108
- }
2109
-
2110
- // ----- Get the result list
2111
- $p_filedescr_list = $v_result_list;
2112
-
2113
- // ----- Return
2114
- return $v_result;
2115
- }
2116
- // --------------------------------------------------------------------------------
2117
-
2118
- // --------------------------------------------------------------------------------
2119
- // Function : privCreate()
2120
- // Description :
2121
- // Parameters :
2122
- // Return Values :
2123
- // --------------------------------------------------------------------------------
2124
- function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
2125
- {
2126
- $v_result=1;
2127
- $v_list_detail = array();
2128
-
2129
- // ----- Magic quotes trick
2130
- $this->privDisableMagicQuotes();
2131
-
2132
- // ----- Open the file in write mode
2133
- if (($v_result = $this->privOpenFd('wb')) != 1)
2134
- {
2135
- // ----- Return
2136
- return $v_result;
2137
- }
2138
-
2139
- // ----- Add the list of files
2140
- $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
2141
-
2142
- // ----- Close
2143
- $this->privCloseFd();
2144
-
2145
- // ----- Magic quotes trick
2146
- $this->privSwapBackMagicQuotes();
2147
-
2148
- // ----- Return
2149
- return $v_result;
2150
- }
2151
- // --------------------------------------------------------------------------------
2152
-
2153
- // --------------------------------------------------------------------------------
2154
- // Function : privAdd()
2155
- // Description :
2156
- // Parameters :
2157
- // Return Values :
2158
- // --------------------------------------------------------------------------------
2159
- function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
2160
- {
2161
- $v_result=1;
2162
- $v_list_detail = array();
2163
-
2164
- // ----- Look if the archive exists or is empty
2165
- if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0))
2166
- {
2167
-
2168
- // ----- Do a create
2169
- $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
2170
-
2171
- // ----- Return
2172
- return $v_result;
2173
- }
2174
- // ----- Magic quotes trick
2175
- $this->privDisableMagicQuotes();
2176
-
2177
- // ----- Open the zip file
2178
- if (($v_result=$this->privOpenFd('rb')) != 1)
2179
- {
2180
- // ----- Magic quotes trick
2181
- $this->privSwapBackMagicQuotes();
2182
-
2183
- // ----- Return
2184
- return $v_result;
2185
- }
2186
-
2187
- // ----- Read the central directory informations
2188
- $v_central_dir = array();
2189
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
2190
- {
2191
- $this->privCloseFd();
2192
- $this->privSwapBackMagicQuotes();
2193
- return $v_result;
2194
- }
2195
-
2196
- // ----- Go to beginning of File
2197
- @rewind($this->zip_fd);
2198
-
2199
- // ----- Creates a temporay file
2200
- $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
2201
-
2202
- // ----- Open the temporary file in write mode
2203
- if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
2204
- {
2205
- $this->privCloseFd();
2206
- $this->privSwapBackMagicQuotes();
2207
-
2208
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
2209
-
2210
- // ----- Return
2211
- return PclZip::errorCode();
2212
- }
2213
-
2214
- // ----- Copy the files from the archive to the temporary file
2215
- // TBC : Here I should better append the file and go back to erase the central dir
2216
- $v_size = $v_central_dir['offset'];
2217
- while ($v_size != 0)
2218
- {
2219
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2220
- $v_buffer = fread($this->zip_fd, $v_read_size);
2221
- @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
2222
- $v_size -= $v_read_size;
2223
- }
2224
-
2225
- // ----- Swap the file descriptor
2226
- // Here is a trick : I swap the temporary fd with the zip fd, in order to use
2227
- // the following methods on the temporary fil and not the real archive
2228
- $v_swap = $this->zip_fd;
2229
- $this->zip_fd = $v_zip_temp_fd;
2230
- $v_zip_temp_fd = $v_swap;
2231
-
2232
- // ----- Add the files
2233
- $v_header_list = array();
2234
- if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
2235
- {
2236
- fclose($v_zip_temp_fd);
2237
- $this->privCloseFd();
2238
- @unlink($v_zip_temp_name);
2239
- $this->privSwapBackMagicQuotes();
2240
-
2241
- // ----- Return
2242
- return $v_result;
2243
- }
2244
-
2245
- // ----- Store the offset of the central dir
2246
- $v_offset = @ftell($this->zip_fd);
2247
-
2248
- // ----- Copy the block of file headers from the old archive
2249
- $v_size = $v_central_dir['size'];
2250
- while ($v_size != 0)
2251
- {
2252
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2253
- $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
2254
- @fwrite($this->zip_fd, $v_buffer, $v_read_size);
2255
- $v_size -= $v_read_size;
2256
- }
2257
-
2258
- // ----- Create the Central Dir files header
2259
- for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++)
2260
- {
2261
- // ----- Create the file header
2262
- if ($v_header_list[$i]['status'] == 'ok') {
2263
- if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
2264
- fclose($v_zip_temp_fd);
2265
- $this->privCloseFd();
2266
- @unlink($v_zip_temp_name);
2267
- $this->privSwapBackMagicQuotes();
2268
-
2269
- // ----- Return
2270
- return $v_result;
2271
- }
2272
- $v_count++;
2273
- }
2274
-
2275
- // ----- Transform the header to a 'usable' info
2276
- $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
2277
- }
2278
-
2279
- // ----- Zip file comment
2280
- $v_comment = $v_central_dir['comment'];
2281
- if (isset($p_options[PCLZIP_OPT_COMMENT])) {
2282
- $v_comment = $p_options[PCLZIP_OPT_COMMENT];
2283
- }
2284
- if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
2285
- $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT];
2286
- }
2287
- if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
2288
- $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment;
2289
- }
2290
-
2291
- // ----- Calculate the size of the central header
2292
- $v_size = @ftell($this->zip_fd)-$v_offset;
2293
-
2294
- // ----- Create the central dir footer
2295
- if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1)
2296
- {
2297
- // ----- Reset the file list
2298
- unset($v_header_list);
2299
- $this->privSwapBackMagicQuotes();
2300
-
2301
- // ----- Return
2302
- return $v_result;
2303
- }
2304
-
2305
- // ----- Swap back the file descriptor
2306
- $v_swap = $this->zip_fd;
2307
- $this->zip_fd = $v_zip_temp_fd;
2308
- $v_zip_temp_fd = $v_swap;
2309
-
2310
- // ----- Close
2311
- $this->privCloseFd();
2312
-
2313
- // ----- Close the temporary file
2314
- @fclose($v_zip_temp_fd);
2315
-
2316
- // ----- Magic quotes trick
2317
- $this->privSwapBackMagicQuotes();
2318
-
2319
- // ----- Delete the zip file
2320
- // TBC : I should test the result ...
2321
- @unlink($this->zipname);
2322
-
2323
- // ----- Rename the temporary file
2324
- // TBC : I should test the result ...
2325
- //@rename($v_zip_temp_name, $this->zipname);
2326
- PclZipUtilRename($v_zip_temp_name, $this->zipname);
2327
-
2328
- // ----- Return
2329
- return $v_result;
2330
- }
2331
- // --------------------------------------------------------------------------------
2332
-
2333
- // --------------------------------------------------------------------------------
2334
- // Function : privOpenFd()
2335
- // Description :
2336
- // Parameters :
2337
- // --------------------------------------------------------------------------------
2338
- function privOpenFd($p_mode)
2339
- {
2340
- $v_result=1;
2341
-
2342
- // ----- Look if already open
2343
- if ($this->zip_fd != 0)
2344
- {
2345
- // ----- Error log
2346
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open');
2347
-
2348
- // ----- Return
2349
- return PclZip::errorCode();
2350
- }
2351
-
2352
- // ----- Open the zip file
2353
- if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0)
2354
- {
2355
- // ----- Error log
2356
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode');
2357
-
2358
- // ----- Return
2359
- return PclZip::errorCode();
2360
- }
2361
-
2362
- // ----- Return
2363
- return $v_result;
2364
- }
2365
- // --------------------------------------------------------------------------------
2366
-
2367
- // --------------------------------------------------------------------------------
2368
- // Function : privCloseFd()
2369
- // Description :
2370
- // Parameters :
2371
- // --------------------------------------------------------------------------------
2372
- function privCloseFd()
2373
- {
2374
- $v_result=1;
2375
-
2376
- if ($this->zip_fd != 0)
2377
- @fclose($this->zip_fd);
2378
- $this->zip_fd = 0;
2379
-
2380
- // ----- Return
2381
- return $v_result;
2382
- }
2383
- // --------------------------------------------------------------------------------
2384
-
2385
- // --------------------------------------------------------------------------------
2386
- // Function : privAddList()
2387
- // Description :
2388
- // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
2389
- // different from the real path of the file. This is usefull if you want to have PclTar
2390
- // running in any directory, and memorize relative path from an other directory.
2391
- // Parameters :
2392
- // $p_list : An array containing the file or directory names to add in the tar
2393
- // $p_result_list : list of added files with their properties (specially the status field)
2394
- // $p_add_dir : Path to add in the filename path archived
2395
- // $p_remove_dir : Path to remove in the filename path archived
2396
- // Return Values :
2397
- // --------------------------------------------------------------------------------
2398
- // function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
2399
- function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
2400
- {
2401
- $v_result=1;
2402
-
2403
- // ----- Add the files
2404
- $v_header_list = array();
2405
- if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
2406
- {
2407
- // ----- Return
2408
- return $v_result;
2409
- }
2410
-
2411
- // ----- Store the offset of the central dir
2412
- $v_offset = @ftell($this->zip_fd);
2413
-
2414
- // ----- Create the Central Dir files header
2415
- for ($i=0,$v_count=0; $i<sizeof($v_header_list); $i++)
2416
- {
2417
- // ----- Create the file header
2418
- if ($v_header_list[$i]['status'] == 'ok') {
2419
- if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
2420
- // ----- Return
2421
- return $v_result;
2422
- }
2423
- $v_count++;
2424
- }
2425
-
2426
- // ----- Transform the header to a 'usable' info
2427
- $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
2428
- }
2429
-
2430
- // ----- Zip file comment
2431
- $v_comment = '';
2432
- if (isset($p_options[PCLZIP_OPT_COMMENT])) {
2433
- $v_comment = $p_options[PCLZIP_OPT_COMMENT];
2434
- }
2435
-
2436
- // ----- Calculate the size of the central header
2437
- $v_size = @ftell($this->zip_fd)-$v_offset;
2438
-
2439
- // ----- Create the central dir footer
2440
- if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1)
2441
- {
2442
- // ----- Reset the file list
2443
- unset($v_header_list);
2444
-
2445
- // ----- Return
2446
- return $v_result;
2447
- }
2448
-
2449
- // ----- Return
2450
- return $v_result;
2451
- }
2452
- // --------------------------------------------------------------------------------
2453
-
2454
- // --------------------------------------------------------------------------------
2455
- // Function : privAddFileList()
2456
- // Description :
2457
- // Parameters :
2458
- // $p_filedescr_list : An array containing the file description
2459
- // or directory names to add in the zip
2460
- // $p_result_list : list of added files with their properties (specially the status field)
2461
- // Return Values :
2462
- // --------------------------------------------------------------------------------
2463
- function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
2464
- {
2465
- $v_result=1;
2466
- $v_header = array();
2467
-
2468
- // ----- Recuperate the current number of elt in list
2469
- $v_nb = sizeof($p_result_list);
2470
-
2471
- // ----- Loop on the files
2472
- for ($j=0; ($j<sizeof($p_filedescr_list)) && ($v_result==1); $j++) {
2473
- // ----- Format the filename
2474
- $p_filedescr_list[$j]['filename']
2475
- = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);
2476
-
2477
-
2478
- // ----- Skip empty file names
2479
- // TBC : Can this be possible ? not checked in DescrParseAtt ?
2480
- if ($p_filedescr_list[$j]['filename'] == "") {
2481
- continue;
2482
- }
2483
-
2484
- // ----- Check the filename
2485
- if ( ($p_filedescr_list[$j]['type'] != 'virtual_file')
2486
- && (!file_exists($p_filedescr_list[$j]['filename']))) {
2487
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$p_filedescr_list[$j]['filename']."' does not exist");
2488
- return PclZip::errorCode();
2489
- }
2490
-
2491
- // ----- Look if it is a file or a dir with no all path remove option
2492
- // or a dir with all its path removed
2493
- // if ( (is_file($p_filedescr_list[$j]['filename']))
2494
- // || ( is_dir($p_filedescr_list[$j]['filename'])
2495
- if ( ($p_filedescr_list[$j]['type'] == 'file')
2496
- || ($p_filedescr_list[$j]['type'] == 'virtual_file')
2497
- || ( ($p_filedescr_list[$j]['type'] == 'folder')
2498
- && ( !isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])
2499
- || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))
2500
- ) {
2501
-
2502
- // ----- Add the file
2503
- $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header,
2504
- $p_options);
2505
- if ($v_result != 1) {
2506
- return $v_result;
2507
- }
2508
-
2509
- // ----- Store the file infos
2510
- $p_result_list[$v_nb++] = $v_header;
2511
- }
2512
- }
2513
-
2514
- // ----- Return
2515
- return $v_result;
2516
- }
2517
- // --------------------------------------------------------------------------------
2518
-
2519
- // --------------------------------------------------------------------------------
2520
- // Function : privAddFile()
2521
- // Description :
2522
- // Parameters :
2523
- // Return Values :
2524
- // --------------------------------------------------------------------------------
2525
- function privAddFile($p_filedescr, &$p_header, &$p_options)
2526
- {
2527
- $v_result=1;
2528
-
2529
- // ----- Working variable
2530
- $p_filename = $p_filedescr['filename'];
2531
-
2532
- // TBC : Already done in the fileAtt check ... ?
2533
- if ($p_filename == "") {
2534
- // ----- Error log
2535
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
2536
-
2537
- // ----- Return
2538
- return PclZip::errorCode();
2539
- }
2540
-
2541
- // ----- Look for a stored different filename
2542
- /* TBC : Removed
2543
- if (isset($p_filedescr['stored_filename'])) {
2544
- $v_stored_filename = $p_filedescr['stored_filename'];
2545
- }
2546
- else {
2547
- $v_stored_filename = $p_filedescr['stored_filename'];
2548
- }
2549
- */
2550
-
2551
- // ----- Set the file properties
2552
- clearstatcache();
2553
- $p_header['version'] = 20;
2554
- $p_header['version_extracted'] = 10;
2555
- $p_header['flag'] = 0;
2556
- $p_header['compression'] = 0;
2557
- $p_header['crc'] = 0;
2558
- $p_header['compressed_size'] = 0;
2559
- $p_header['filename_len'] = strlen($p_filename);
2560
- $p_header['extra_len'] = 0;
2561
- $p_header['disk'] = 0;
2562
- $p_header['internal'] = 0;
2563
- $p_header['offset'] = 0;
2564
- $p_header['filename'] = $p_filename;
2565
- // TBC : Removed $p_header['stored_filename'] = $v_stored_filename;
2566
- $p_header['stored_filename'] = $p_filedescr['stored_filename'];
2567
- $p_header['extra'] = '';
2568
- $p_header['status'] = 'ok';
2569
- $p_header['index'] = -1;
2570
-
2571
- // ----- Look for regular file
2572
- if ($p_filedescr['type']=='file') {
2573
- $p_header['external'] = 0x00000000;
2574
- $p_header['size'] = filesize($p_filename);
2575
- }
2576
-
2577
- // ----- Look for regular folder
2578
- else if ($p_filedescr['type']=='folder') {
2579
- $p_header['external'] = 0x00000010;
2580
- $p_header['mtime'] = filemtime($p_filename);
2581
- $p_header['size'] = filesize($p_filename);
2582
- }
2583
-
2584
- // ----- Look for virtual file
2585
- else if ($p_filedescr['type'] == 'virtual_file') {
2586
- $p_header['external'] = 0x00000000;
2587
- $p_header['size'] = strlen($p_filedescr['content']);
2588
- }
2589
-
2590
-
2591
- // ----- Look for filetime
2592
- if (isset($p_filedescr['mtime'])) {
2593
- $p_header['mtime'] = $p_filedescr['mtime'];
2594
- }
2595
- else if ($p_filedescr['type'] == 'virtual_file') {
2596
- $p_header['mtime'] = time();
2597
- }
2598
- else {
2599
- $p_header['mtime'] = filemtime($p_filename);
2600
- }
2601
-
2602
- // ------ Look for file comment
2603
- if (isset($p_filedescr['comment'])) {
2604
- $p_header['comment_len'] = strlen($p_filedescr['comment']);
2605
- $p_header['comment'] = $p_filedescr['comment'];
2606
- }
2607
- else {
2608
- $p_header['comment_len'] = 0;
2609
- $p_header['comment'] = '';
2610
- }
2611
-
2612
- // ----- Look for pre-add callback
2613
- if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
2614
-
2615
- // ----- Generate a local information
2616
- $v_local_header = array();
2617
- $this->privConvertHeader2FileInfo($p_header, $v_local_header);
2618
-
2619
- // ----- Call the callback
2620
- // Here I do not use call_user_func() because I need to send a reference to the
2621
- // header.
2622
- // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
2623
- $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
2624
- if ($v_result == 0) {
2625
- // ----- Change the file status
2626
- $p_header['status'] = "skipped";
2627
- $v_result = 1;
2628
- }
2629
-
2630
- // ----- Update the informations
2631
- // Only some fields can be modified
2632
- if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
2633
- $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
2634
- }
2635
- }
2636
-
2637
- // ----- Look for empty stored filename
2638
- if ($p_header['stored_filename'] == "") {
2639
- $p_header['status'] = "filtered";
2640
- }
2641
-
2642
- // ----- Check the path length
2643
- if (strlen($p_header['stored_filename']) > 0xFF) {
2644
- $p_header['status'] = 'filename_too_long';
2645
- }
2646
-
2647
- // ----- Look if no error, or file not skipped
2648
- if ($p_header['status'] == 'ok') {
2649
-
2650
- // ----- Look for a file
2651
- if ($p_filedescr['type'] == 'file') {
2652
- // ----- Look for using temporary file to zip
2653
- if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
2654
- && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
2655
- || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
2656
- && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) {
2657
- $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
2658
- if ($v_result < PCLZIP_ERR_NO_ERROR) {
2659
- return $v_result;
2660
- }
2661
- }
2662
-
2663
- // ----- Use "in memory" zip algo
2664
- else {
2665
-
2666
- // ----- Open the source file
2667
- if (($v_file = @fopen($p_filename, "rb")) == 0) {
2668
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
2669
- return PclZip::errorCode();
2670
- }
2671
-
2672
- // ----- Read the file content
2673
- $v_content = @fread($v_file, $p_header['size']);
2674
-
2675
- // ----- Close the file
2676
- @fclose($v_file);
2677
-
2678
- // ----- Calculate the CRC
2679
- $p_header['crc'] = @crc32($v_content);
2680
-
2681
- // ----- Look for no compression
2682
- if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
2683
- // ----- Set header parameters
2684
- $p_header['compressed_size'] = $p_header['size'];
2685
- $p_header['compression'] = 0;
2686
- }
2687
-
2688
- // ----- Look for normal compression
2689
- else {
2690
- // ----- Compress the content
2691
- $v_content = @gzdeflate($v_content);
2692
-
2693
- // ----- Set header parameters
2694
- $p_header['compressed_size'] = strlen($v_content);
2695
- $p_header['compression'] = 8;
2696
- }
2697
-
2698
- // ----- Call the header generation
2699
- if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2700
- @fclose($v_file);
2701
- return $v_result;
2702
- }
2703
-
2704
- // ----- Write the compressed (or not) content
2705
- @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
2706
-
2707
- }
2708
-
2709
- }
2710
-
2711
- // ----- Look for a virtual file (a file from string)
2712
- else if ($p_filedescr['type'] == 'virtual_file') {
2713
-
2714
- $v_content = $p_filedescr['content'];
2715
-
2716
- // ----- Calculate the CRC
2717
- $p_header['crc'] = @crc32($v_content);
2718
-
2719
- // ----- Look for no compression
2720
- if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
2721
- // ----- Set header parameters
2722
- $p_header['compressed_size'] = $p_header['size'];
2723
- $p_header['compression'] = 0;
2724
- }
2725
-
2726
- // ----- Look for normal compression
2727
- else {
2728
- // ----- Compress the content
2729
- $v_content = @gzdeflate($v_content);
2730
-
2731
- // ----- Set header parameters
2732
- $p_header['compressed_size'] = strlen($v_content);
2733
- $p_header['compression'] = 8;
2734
- }
2735
-
2736
- // ----- Call the header generation
2737
- if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2738
- @fclose($v_file);
2739
- return $v_result;
2740
- }
2741
-
2742
- // ----- Write the compressed (or not) content
2743
- @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
2744
- }
2745
-
2746
- // ----- Look for a directory
2747
- else if ($p_filedescr['type'] == 'folder') {
2748
- // ----- Look for directory last '/'
2749
- if (@substr($p_header['stored_filename'], -1) != '/') {
2750
- $p_header['stored_filename'] .= '/';
2751
- }
2752
-
2753
- // ----- Set the file properties
2754
- $p_header['size'] = 0;
2755
- //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked
2756
- $p_header['external'] = 0x00000010; // Value for a folder : to be checked
2757
-
2758
- // ----- Call the header generation
2759
- if (($v_result = $this->privWriteFileHeader($p_header)) != 1)
2760
- {
2761
- return $v_result;
2762
- }
2763
- }
2764
- }
2765
-
2766
- // ----- Look for post-add callback
2767
- if (isset($p_options[PCLZIP_CB_POST_ADD])) {
2768
-
2769
- // ----- Generate a local information
2770
- $v_local_header = array();
2771
- $this->privConvertHeader2FileInfo($p_header, $v_local_header);
2772
-
2773
- // ----- Call the callback
2774
- // Here I do not use call_user_func() because I need to send a reference to the
2775
- // header.
2776
- // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
2777
- $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
2778
- if ($v_result == 0) {
2779
- // ----- Ignored
2780
- $v_result = 1;
2781
- }
2782
-
2783
- // ----- Update the informations
2784
- // Nothing can be modified
2785
- }
2786
-
2787
- // ----- Return
2788
- return $v_result;
2789
- }
2790
- // --------------------------------------------------------------------------------
2791
-
2792
- // --------------------------------------------------------------------------------
2793
- // Function : privAddFileUsingTempFile()
2794
- // Description :
2795
- // Parameters :
2796
- // Return Values :
2797
- // --------------------------------------------------------------------------------
2798
- function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
2799
- {
2800
- $v_result=PCLZIP_ERR_NO_ERROR;
2801
-
2802
- // ----- Working variable
2803
- $p_filename = $p_filedescr['filename'];
2804
-
2805
-
2806
- // ----- Open the source file
2807
- if (($v_file = @fopen($p_filename, "rb")) == 0) {
2808
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
2809
- return PclZip::errorCode();
2810
- }
2811
-
2812
- // ----- Creates a compressed temporary file
2813
- $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
2814
- if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
2815
- fclose($v_file);
2816
- PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
2817
- return PclZip::errorCode();
2818
- }
2819
-
2820
- // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
2821
- $v_size = filesize($p_filename);
2822
- while ($v_size != 0) {
2823
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2824
- $v_buffer = @fread($v_file, $v_read_size);
2825
- //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
2826
- @gzputs($v_file_compressed, $v_buffer, $v_read_size);
2827
- $v_size -= $v_read_size;
2828
- }
2829
-
2830
- // ----- Close the file
2831
- @fclose($v_file);
2832
- @gzclose($v_file_compressed);
2833
-
2834
- // ----- Check the minimum file size
2835
- if (filesize($v_gzip_temp_name) < 18) {
2836
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes');
2837
- return PclZip::errorCode();
2838
- }
2839
-
2840
- // ----- Extract the compressed attributes
2841
- if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
2842
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
2843
- return PclZip::errorCode();
2844
- }
2845
-
2846
- // ----- Read the gzip file header
2847
- $v_binary_data = @fread($v_file_compressed, 10);
2848
- $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
2849
-
2850
- // ----- Check some parameters
2851
- $v_data_header['os'] = bin2hex($v_data_header['os']);
2852
-
2853
- // ----- Read the gzip file footer
2854
- @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8);
2855
- $v_binary_data = @fread($v_file_compressed, 8);
2856
- $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
2857
-
2858
- // ----- Set the attributes
2859
- $p_header['compression'] = ord($v_data_header['cm']);
2860
- //$p_header['mtime'] = $v_data_header['mtime'];
2861
- $p_header['crc'] = $v_data_footer['crc'];
2862
- $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18;
2863
-
2864
- // ----- Close the file
2865
- @fclose($v_file_compressed);
2866
-
2867
- // ----- Call the header generation
2868
- if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2869
- return $v_result;
2870
- }
2871
-
2872
- // ----- Add the compressed data
2873
- if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0)
2874
- {
2875
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
2876
- return PclZip::errorCode();
2877
- }
2878
-
2879
- // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
2880
- fseek($v_file_compressed, 10);
2881
- $v_size = $p_header['compressed_size'];
2882
- while ($v_size != 0)
2883
- {
2884
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2885
- $v_buffer = @fread($v_file_compressed, $v_read_size);
2886
- //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
2887
- @fwrite($this->zip_fd, $v_buffer, $v_read_size);
2888
- $v_size -= $v_read_size;
2889
- }
2890
-
2891
- // ----- Close the file
2892
- @fclose($v_file_compressed);
2893
-
2894
- // ----- Unlink the temporary file
2895
- @unlink($v_gzip_temp_name);
2896
-
2897
- // ----- Return
2898
- return $v_result;
2899
- }
2900
- // --------------------------------------------------------------------------------
2901
-
2902
- // --------------------------------------------------------------------------------
2903
- // Function : privCalculateStoredFilename()
2904
- // Description :
2905
- // Based on file descriptor properties and global options, this method
2906
- // calculate the filename that will be stored in the archive.
2907
- // Parameters :
2908
- // Return Values :
2909
- // --------------------------------------------------------------------------------
2910
- function privCalculateStoredFilename(&$p_filedescr, &$p_options)
2911
- {
2912
- $v_result=1;
2913
-
2914
- // ----- Working variables
2915
- $p_filename = $p_filedescr['filename'];
2916
- if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
2917
- $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
2918
- }
2919
- else {
2920
- $p_add_dir = '';
2921
- }
2922
- if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
2923
- $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
2924
- }
2925
- else {
2926
- $p_remove_dir = '';
2927
- }
2928
- if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
2929
- $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
2930
- }
2931
- else {
2932
- $p_remove_all_dir = 0;
2933
- }
2934
-
2935
-
2936
- // ----- Look for full name change
2937
- if (isset($p_filedescr['new_full_name'])) {
2938
- // ----- Remove drive letter if any
2939
- $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
2940
- }
2941
-
2942
- // ----- Look for path and/or short name change
2943
- else {
2944
-
2945
- // ----- Look for short name change
2946
- // Its when we cahnge just the filename but not the path
2947
- if (isset($p_filedescr['new_short_name'])) {
2948
- $v_path_info = pathinfo($p_filename);
2949
- $v_dir = '';
2950
- if ($v_path_info['dirname'] != '') {
2951
- $v_dir = $v_path_info['dirname'].'/';
2952
- }
2953
- $v_stored_filename = $v_dir.$p_filedescr['new_short_name'];
2954
- }
2955
- else {
2956
- // ----- Calculate the stored filename
2957
- $v_stored_filename = $p_filename;
2958
- }
2959
-
2960
- // ----- Look for all path to remove
2961
- if ($p_remove_all_dir) {
2962
- $v_stored_filename = basename($p_filename);
2963
- }
2964
- // ----- Look for partial path remove
2965
- else if ($p_remove_dir != "") {
2966
- if (substr($p_remove_dir, -1) != '/')
2967
- $p_remove_dir .= "/";
2968
-
2969
- if ( (substr($p_filename, 0, 2) == "./")
2970
- || (substr($p_remove_dir, 0, 2) == "./")) {
2971
-
2972
- if ( (substr($p_filename, 0, 2) == "./")
2973
- && (substr($p_remove_dir, 0, 2) != "./")) {
2974
- $p_remove_dir = "./".$p_remove_dir;
2975
- }
2976
- if ( (substr($p_filename, 0, 2) != "./")
2977
- && (substr($p_remove_dir, 0, 2) == "./")) {
2978
- $p_remove_dir = substr($p_remove_dir, 2);
2979
- }
2980
- }
2981
-
2982
- $v_compare = PclZipUtilPathInclusion($p_remove_dir,
2983
- $v_stored_filename);
2984
- if ($v_compare > 0) {
2985
- if ($v_compare == 2) {
2986
- $v_stored_filename = "";
2987
- }
2988
- else {
2989
- $v_stored_filename = substr($v_stored_filename,
2990
- strlen($p_remove_dir));
2991
- }
2992
- }
2993
- }
2994
-
2995
- // ----- Remove drive letter if any
2996
- $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
2997
-
2998
- // ----- Look for path to add
2999
- if ($p_add_dir != "") {
3000
- if (substr($p_add_dir, -1) == "/")
3001
- $v_stored_filename = $p_add_dir.$v_stored_filename;
3002
- else
3003
- $v_stored_filename = $p_add_dir."/".$v_stored_filename;
3004
- }
3005
- }
3006
-
3007
- // ----- Filename (reduce the path of stored name)
3008
- $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
3009
- $p_filedescr['stored_filename'] = $v_stored_filename;
3010
-
3011
- // ----- Return
3012
- return $v_result;
3013
- }
3014
- // --------------------------------------------------------------------------------
3015
-
3016
- // --------------------------------------------------------------------------------
3017
- // Function : privWriteFileHeader()
3018
- // Description :
3019
- // Parameters :
3020
- // Return Values :
3021
- // --------------------------------------------------------------------------------
3022
- function privWriteFileHeader(&$p_header)
3023
- {
3024
- $v_result=1;
3025
-
3026
- // ----- Store the offset position of the file
3027
- $p_header['offset'] = ftell($this->zip_fd);
3028
-
3029
- // ----- Transform UNIX mtime to DOS format mdate/mtime
3030
- $v_date = getdate($p_header['mtime']);
3031
- $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
3032
- $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
3033
-
3034
- // ----- Packed data
3035
- $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50,
3036
- $p_header['version_extracted'], $p_header['flag'],
3037
- $p_header['compression'], $v_mtime, $v_mdate,
3038
- $p_header['crc'], $p_header['compressed_size'],
3039
- $p_header['size'],
3040
- strlen($p_header['stored_filename']),
3041
- $p_header['extra_len']);
3042
-
3043
- // ----- Write the first 148 bytes of the header in the archive
3044
- fputs($this->zip_fd, $v_binary_data, 30);
3045
-
3046
- // ----- Write the variable fields
3047
- if (strlen($p_header['stored_filename']) != 0)
3048
- {
3049
- fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
3050
- }
3051
- if ($p_header['extra_len'] != 0)
3052
- {
3053
- fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
3054
- }
3055
-
3056
- // ----- Return
3057
- return $v_result;
3058
- }
3059
- // --------------------------------------------------------------------------------
3060
-
3061
- // --------------------------------------------------------------------------------
3062
- // Function : privWriteCentralFileHeader()
3063
- // Description :
3064
- // Parameters :
3065
- // Return Values :
3066
- // --------------------------------------------------------------------------------
3067
- function privWriteCentralFileHeader(&$p_header)
3068
- {
3069
- $v_result=1;
3070
-
3071
- // TBC
3072
- //for(reset($p_header); $key = key($p_header); next($p_header)) {
3073
- //}
3074
-
3075
- // ----- Transform UNIX mtime to DOS format mdate/mtime
3076
- $v_date = getdate($p_header['mtime']);
3077
- $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
3078
- $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
3079
-
3080
-
3081
- // ----- Packed data
3082
- $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50,
3083
- $p_header['version'], $p_header['version_extracted'],
3084
- $p_header['flag'], $p_header['compression'],
3085
- $v_mtime, $v_mdate, $p_header['crc'],
3086
- $p_header['compressed_size'], $p_header['size'],
3087
- strlen($p_header['stored_filename']),
3088
- $p_header['extra_len'], $p_header['comment_len'],
3089
- $p_header['disk'], $p_header['internal'],
3090
- $p_header['external'], $p_header['offset']);
3091
-
3092
- // ----- Write the 42 bytes of the header in the zip file
3093
- fputs($this->zip_fd, $v_binary_data, 46);
3094
-
3095
- // ----- Write the variable fields
3096
- if (strlen($p_header['stored_filename']) != 0)
3097
- {
3098
- fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
3099
- }
3100
- if ($p_header['extra_len'] != 0)
3101
- {
3102
- fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
3103
- }
3104
- if ($p_header['comment_len'] != 0)
3105
- {
3106
- fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
3107
- }
3108
-
3109
- // ----- Return
3110
- return $v_result;
3111
- }
3112
- // --------------------------------------------------------------------------------
3113
-
3114
- // --------------------------------------------------------------------------------
3115
- // Function : privWriteCentralHeader()
3116
- // Description :
3117
- // Parameters :
3118
- // Return Values :
3119
- // --------------------------------------------------------------------------------
3120
- function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
3121
- {
3122
- $v_result=1;
3123
-
3124
- // ----- Packed data
3125
- $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries,
3126
- $p_nb_entries, $p_size,
3127
- $p_offset, strlen($p_comment));
3128
-
3129
- // ----- Write the 22 bytes of the header in the zip file
3130
- fputs($this->zip_fd, $v_binary_data, 22);
3131
-
3132
- // ----- Write the variable fields
3133
- if (strlen($p_comment) != 0)
3134
- {
3135
- fputs($this->zip_fd, $p_comment, strlen($p_comment));
3136
- }
3137
-
3138
- // ----- Return
3139
- return $v_result;
3140
- }
3141
- // --------------------------------------------------------------------------------
3142
-
3143
- // --------------------------------------------------------------------------------
3144
- // Function : privList()
3145
- // Description :
3146
- // Parameters :
3147
- // Return Values :
3148
- // --------------------------------------------------------------------------------
3149
- function privList(&$p_list)
3150
- {
3151
- $v_result=1;
3152
-
3153
- // ----- Magic quotes trick
3154
- $this->privDisableMagicQuotes();
3155
-
3156
- // ----- Open the zip file
3157
- if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
3158
- {
3159
- // ----- Magic quotes trick
3160
- $this->privSwapBackMagicQuotes();
3161
-
3162
- // ----- Error log
3163
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
3164
-
3165
- // ----- Return
3166
- return PclZip::errorCode();
3167
- }
3168
-
3169
- // ----- Read the central directory informations
3170
- $v_central_dir = array();
3171
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
3172
- {
3173
- $this->privSwapBackMagicQuotes();
3174
- return $v_result;
3175
- }
3176
-
3177
- // ----- Go to beginning of Central Dir
3178
- @rewind($this->zip_fd);
3179
- if (@fseek($this->zip_fd, $v_central_dir['offset']))
3180
- {
3181
- $this->privSwapBackMagicQuotes();
3182
-
3183
- // ----- Error log
3184
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
3185
-
3186
- // ----- Return
3187
- return PclZip::errorCode();
3188
- }
3189
-
3190
- // ----- Read each entry
3191
- for ($i=0; $i<$v_central_dir['entries']; $i++)
3192
- {
3193
- // ----- Read the file header
3194
- if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
3195
- {
3196
- $this->privSwapBackMagicQuotes();
3197
- return $v_result;
3198
- }
3199
- $v_header['index'] = $i;
3200
-
3201
- // ----- Get the only interesting attributes
3202
- $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
3203
- unset($v_header);
3204
- }
3205
-
3206
- // ----- Close the zip file
3207
- $this->privCloseFd();
3208
-
3209
- // ----- Magic quotes trick
3210
- $this->privSwapBackMagicQuotes();
3211
-
3212
- // ----- Return
3213
- return $v_result;
3214
- }
3215
- // --------------------------------------------------------------------------------
3216
-
3217
- // --------------------------------------------------------------------------------
3218
- // Function : privConvertHeader2FileInfo()
3219
- // Description :
3220
- // This function takes the file informations from the central directory
3221
- // entries and extract the interesting parameters that will be given back.
3222
- // The resulting file infos are set in the array $p_info
3223
- // $p_info['filename'] : Filename with full path. Given by user (add),
3224
- // extracted in the filesystem (extract).
3225
- // $p_info['stored_filename'] : Stored filename in the archive.
3226
- // $p_info['size'] = Size of the file.
3227
- // $p_info['compressed_size'] = Compressed size of the file.
3228
- // $p_info['mtime'] = Last modification date of the file.
3229
- // $p_info['comment'] = Comment associated with the file.
3230
- // $p_info['folder'] = true/false : indicates if the entry is a folder or not.
3231
- // $p_info['status'] = status of the action on the file.
3232
- // $p_info['crc'] = CRC of the file content.
3233
- // Parameters :
3234
- // Return Values :
3235
- // --------------------------------------------------------------------------------
3236
- function privConvertHeader2FileInfo($p_header, &$p_info)
3237
- {
3238
- $v_result=1;
3239
-
3240
- // ----- Get the interesting attributes
3241
- $v_temp_path = PclZipUtilPathReduction($p_header['filename']);
3242
- $p_info['filename'] = $v_temp_path;
3243
- $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']);
3244
- $p_info['stored_filename'] = $v_temp_path;
3245
- $p_info['size'] = $p_header['size'];
3246
- $p_info['compressed_size'] = $p_header['compressed_size'];
3247
- $p_info['mtime'] = $p_header['mtime'];
3248
- $p_info['comment'] = $p_header['comment'];
3249
- $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010);
3250
- $p_info['index'] = $p_header['index'];
3251
- $p_info['status'] = $p_header['status'];
3252
- $p_info['crc'] = $p_header['crc'];
3253
-
3254
- // ----- Return
3255
- return $v_result;
3256
- }
3257
- // --------------------------------------------------------------------------------
3258
-
3259
- // --------------------------------------------------------------------------------
3260
- // Function : privExtractByRule()
3261
- // Description :
3262
- // Extract a file or directory depending of rules (by index, by name, ...)
3263
- // Parameters :
3264
- // $p_file_list : An array where will be placed the properties of each
3265
- // extracted file
3266
- // $p_path : Path to add while writing the extracted files
3267
- // $p_remove_path : Path to remove (from the file memorized path) while writing the
3268
- // extracted files. If the path does not match the file path,
3269
- // the file is extracted with its memorized path.
3270
- // $p_remove_path does not apply to 'list' mode.
3271
- // $p_path and $p_remove_path are commulative.
3272
- // Return Values :
3273
- // 1 on success,0 or less on error (see error code list)
3274
- // --------------------------------------------------------------------------------
3275
- function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
3276
- {
3277
- $v_result=1;
3278
-
3279
- // ----- Magic quotes trick
3280
- $this->privDisableMagicQuotes();
3281
-
3282
- // ----- Check the path
3283
- if ( ($p_path == "")
3284
- || ( (substr($p_path, 0, 1) != "/")
3285
- && (substr($p_path, 0, 3) != "../")
3286
- && (substr($p_path,1,2)!=":/")))
3287
- $p_path = "./".$p_path;
3288
-
3289
- // ----- Reduce the path last (and duplicated) '/'
3290
- if (($p_path != "./") && ($p_path != "/"))
3291
- {
3292
- // ----- Look for the path end '/'
3293
- while (substr($p_path, -1) == "/")
3294
- {
3295
- $p_path = substr($p_path, 0, strlen($p_path)-1);
3296
- }
3297
- }
3298
-
3299
- // ----- Look for path to remove format (should end by /)
3300
- if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/'))
3301
- {
3302
- $p_remove_path .= '/';
3303
- }
3304
- $p_remove_path_size = strlen($p_remove_path);
3305
-
3306
- // ----- Open the zip file
3307
- if (($v_result = $this->privOpenFd('rb')) != 1)
3308
- {
3309
- $this->privSwapBackMagicQuotes();
3310
- return $v_result;
3311
- }
3312
-
3313
- // ----- Read the central directory informations
3314
- $v_central_dir = array();
3315
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
3316
- {
3317
- // ----- Close the zip file
3318
- $this->privCloseFd();
3319
- $this->privSwapBackMagicQuotes();
3320
-
3321
- return $v_result;
3322
- }
3323
-
3324
- // ----- Start at beginning of Central Dir
3325
- $v_pos_entry = $v_central_dir['offset'];
3326
-
3327
- // ----- Read each entry
3328
- $j_start = 0;
3329
- for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
3330
- {
3331
-
3332
- // ----- Read next Central dir entry
3333
- @rewind($this->zip_fd);
3334
- if (@fseek($this->zip_fd, $v_pos_entry))
3335
- {
3336
- // ----- Close the zip file
3337
- $this->privCloseFd();
3338
- $this->privSwapBackMagicQuotes();
3339
-
3340
- // ----- Error log
3341
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
3342
-
3343
- // ----- Return
3344
- return PclZip::errorCode();
3345
- }
3346
-
3347
- // ----- Read the file header
3348
- $v_header = array();
3349
- if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
3350
- {
3351
- // ----- Close the zip file
3352
- $this->privCloseFd();
3353
- $this->privSwapBackMagicQuotes();
3354
-
3355
- return $v_result;
3356
- }
3357
-
3358
- // ----- Store the index
3359
- $v_header['index'] = $i;
3360
-
3361
- // ----- Store the file position
3362
- $v_pos_entry = ftell($this->zip_fd);
3363
-
3364
- // ----- Look for the specific extract rules
3365
- $v_extract = false;
3366
-
3367
- // ----- Look for extract by name rule
3368
- if ( (isset($p_options[PCLZIP_OPT_BY_NAME]))
3369
- && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
3370
-
3371
- // ----- Look if the filename is in the list
3372
- for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) {
3373
-
3374
- // ----- Look for a directory
3375
- if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
3376
-
3377
- // ----- Look if the directory is in the filename path
3378
- if ( (strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
3379
- && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
3380
- $v_extract = true;
3381
- }
3382
- }
3383
- // ----- Look for a filename
3384
- elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
3385
- $v_extract = true;
3386
- }
3387
- }
3388
- }
3389
-
3390
- // ----- Look for extract by ereg rule
3391
- // ereg() is deprecated with PHP 5.3
3392
- /*
3393
- else if ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
3394
- && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
3395
-
3396
- if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) {
3397
- $v_extract = true;
3398
- }
3399
- }
3400
- */
3401
-
3402
- // ----- Look for extract by preg rule
3403
- else if ( (isset($p_options[PCLZIP_OPT_BY_PREG]))
3404
- && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
3405
-
3406
- if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
3407
- $v_extract = true;
3408
- }
3409
- }
3410
-
3411
- // ----- Look for extract by index rule
3412
- else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX]))
3413
- && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
3414
-
3415
- // ----- Look if the index is in the list
3416
- for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) {
3417
-
3418
- if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
3419
- $v_extract = true;
3420
- }
3421
- if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
3422
- $j_start = $j+1;
3423
- }
3424
-
3425
- if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
3426
- break;
3427
- }
3428
- }
3429
- }
3430
-
3431
- // ----- Look for no rule, which means extract all the archive
3432
- else {
3433
- $v_extract = true;
3434
- }
3435
-
3436
- // ----- Check compression method
3437
- if ( ($v_extract)
3438
- && ( ($v_header['compression'] != 8)
3439
- && ($v_header['compression'] != 0))) {
3440
- $v_header['status'] = 'unsupported_compression';
3441
-
3442
- // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3443
- if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
3444
- && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
3445
-
3446
- $this->privSwapBackMagicQuotes();
3447
-
3448
- PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION,
3449
- "Filename '".$v_header['stored_filename']."' is "
3450
- ."compressed by an unsupported compression "
3451
- ."method (".$v_header['compression'].") ");
3452
-
3453
- return PclZip::errorCode();
3454
- }
3455
- }
3456
-
3457
- // ----- Check encrypted files
3458
- if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
3459
- $v_header['status'] = 'unsupported_encryption';
3460
-
3461
- // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3462
- if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
3463
- && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
3464
-
3465
- $this->privSwapBackMagicQuotes();
3466
-
3467
- PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION,
3468
- "Unsupported encryption for "
3469
- ." filename '".$v_header['stored_filename']
3470
- ."'");
3471
-
3472
- return PclZip::errorCode();
3473
- }
3474
- }
3475
-
3476
- // ----- Look for real extraction
3477
- if (($v_extract) && ($v_header['status'] != 'ok')) {
3478
- $v_result = $this->privConvertHeader2FileInfo($v_header,
3479
- $p_file_list[$v_nb_extracted++]);
3480
- if ($v_result != 1) {
3481
- $this->privCloseFd();
3482
- $this->privSwapBackMagicQuotes();
3483
- return $v_result;
3484
- }
3485
-
3486
- $v_extract = false;
3487
- }
3488
-
3489
- // ----- Look for real extraction
3490
- if ($v_extract)
3491
- {
3492
-
3493
- // ----- Go to the file position
3494
- @rewind($this->zip_fd);
3495
- if (@fseek($this->zip_fd, $v_header['offset']))
3496
- {
3497
- // ----- Close the zip file
3498
- $this->privCloseFd();
3499
-
3500
- $this->privSwapBackMagicQuotes();
3501
-
3502
- // ----- Error log
3503
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
3504
-
3505
- // ----- Return
3506
- return PclZip::errorCode();
3507
- }
3508
-
3509
- // ----- Look for extraction as string
3510
- if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
3511
-
3512
- $v_string = '';
3513
-
3514
- // ----- Extracting the file
3515
- $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
3516
- if ($v_result1 < 1) {
3517
- $this->privCloseFd();
3518
- $this->privSwapBackMagicQuotes();
3519
- return $v_result1;
3520
- }
3521
-
3522
- // ----- Get the only interesting attributes
3523
- if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1)
3524
- {
3525
- // ----- Close the zip file
3526
- $this->privCloseFd();
3527
- $this->privSwapBackMagicQuotes();
3528
-
3529
- return $v_result;
3530
- }
3531
-
3532
- // ----- Set the file content
3533
- $p_file_list[$v_nb_extracted]['content'] = $v_string;
3534
-
3535
- // ----- Next extracted file
3536
- $v_nb_extracted++;
3537
-
3538
- // ----- Look for user callback abort
3539
- if ($v_result1 == 2) {
3540
- break;
3541
- }
3542
- }
3543
- // ----- Look for extraction in standard output
3544
- elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT]))
3545
- && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {
3546
- // ----- Extracting the file in standard output
3547
- $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
3548
- if ($v_result1 < 1) {
3549
- $this->privCloseFd();
3550
- $this->privSwapBackMagicQuotes();
3551
- return $v_result1;
3552
- }
3553
-
3554
- // ----- Get the only interesting attributes
3555
- if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
3556
- $this->privCloseFd();
3557
- $this->privSwapBackMagicQuotes();
3558
- return $v_result;
3559
- }
3560
-
3561
- // ----- Look for user callback abort
3562
- if ($v_result1 == 2) {
3563
- break;
3564
- }
3565
- }
3566
- // ----- Look for normal extraction
3567
- else {
3568
- // ----- Extracting the file
3569
- $v_result1 = $this->privExtractFile($v_header,
3570
- $p_path, $p_remove_path,
3571
- $p_remove_all_path,
3572
- $p_options);
3573
- if ($v_result1 < 1) {
3574
- $this->privCloseFd();
3575
- $this->privSwapBackMagicQuotes();
3576
- return $v_result1;
3577
- }
3578
-
3579
- // ----- Get the only interesting attributes
3580
- if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1)
3581
- {
3582
- // ----- Close the zip file
3583
- $this->privCloseFd();
3584
- $this->privSwapBackMagicQuotes();
3585
-
3586
- return $v_result;
3587
- }
3588
-
3589
- // ----- Look for user callback abort
3590
- if ($v_result1 == 2) {
3591
- break;
3592
- }
3593
- }
3594
- }
3595
- }
3596
-
3597
- // ----- Close the zip file
3598
- $this->privCloseFd();
3599
- $this->privSwapBackMagicQuotes();
3600
-
3601
- // ----- Return
3602
- return $v_result;
3603
- }
3604
- // --------------------------------------------------------------------------------
3605
-
3606
- // --------------------------------------------------------------------------------
3607
- // Function : privExtractFile()
3608
- // Description :
3609
- // Parameters :
3610
- // Return Values :
3611
- //
3612
- // 1 : ... ?
3613
- // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
3614
- // --------------------------------------------------------------------------------
3615
- function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
3616
- {
3617
- $v_result=1;
3618
-
3619
- // ----- Read the file header
3620
- if (($v_result = $this->privReadFileHeader($v_header)) != 1)
3621
- {
3622
- // ----- Return
3623
- return $v_result;
3624
- }
3625
-
3626
-
3627
- // ----- Check that the file header is coherent with $p_entry info
3628
- if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
3629
- // TBC
3630
- }
3631
-
3632
- // ----- Look for all path to remove
3633
- if ($p_remove_all_path == true) {
3634
- // ----- Look for folder entry that not need to be extracted
3635
- if (($p_entry['external']&0x00000010)==0x00000010) {
3636
-
3637
- $p_entry['status'] = "filtered";
3638
-
3639
- return $v_result;
3640
- }
3641
-
3642
- // ----- Get the basename of the path
3643
- $p_entry['filename'] = basename($p_entry['filename']);
3644
- }
3645
-
3646
- // ----- Look for path to remove
3647
- else if ($p_remove_path != "")
3648
- {
3649
- if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2)
3650
- {
3651
-
3652
- // ----- Change the file status
3653
- $p_entry['status'] = "filtered";
3654
-
3655
- // ----- Return
3656
- return $v_result;
3657
- }
3658
-
3659
- $p_remove_path_size = strlen($p_remove_path);
3660
- if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path)
3661
- {
3662
-
3663
- // ----- Remove the path
3664
- $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
3665
-
3666
- }
3667
- }
3668
-
3669
- // ----- Add the path
3670
- if ($p_path != '') {
3671
- $p_entry['filename'] = $p_path."/".$p_entry['filename'];
3672
- }
3673
-
3674
- // ----- Check a base_dir_restriction
3675
- if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
3676
- $v_inclusion
3677
- = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION],
3678
- $p_entry['filename']);
3679
- if ($v_inclusion == 0) {
3680
-
3681
- PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION,
3682
- "Filename '".$p_entry['filename']."' is "
3683
- ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
3684
-
3685
- return PclZip::errorCode();
3686
- }
3687
- }
3688
-
3689
- // ----- Look for pre-extract callback
3690
- if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
3691
-
3692
- // ----- Generate a local information
3693
- $v_local_header = array();
3694
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
3695
-
3696
- // ----- Call the callback
3697
- // Here I do not use call_user_func() because I need to send a reference to the
3698
- // header.
3699
- // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
3700
- $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
3701
- if ($v_result == 0) {
3702
- // ----- Change the file status
3703
- $p_entry['status'] = "skipped";
3704
- $v_result = 1;
3705
- }
3706
-
3707
- // ----- Look for abort result
3708
- if ($v_result == 2) {
3709
- // ----- This status is internal and will be changed in 'skipped'
3710
- $p_entry['status'] = "aborted";
3711
- $v_result = PCLZIP_ERR_USER_ABORTED;
3712
- }
3713
-
3714
- // ----- Update the informations
3715
- // Only some fields can be modified
3716
- $p_entry['filename'] = $v_local_header['filename'];
3717
- }
3718
-
3719
-
3720
- // ----- Look if extraction should be done
3721
- if ($p_entry['status'] == 'ok') {
3722
-
3723
- // ----- Look for specific actions while the file exist
3724
- if (file_exists($p_entry['filename']))
3725
- {
3726
-
3727
- // ----- Look if file is a directory
3728
- if (is_dir($p_entry['filename']))
3729
- {
3730
-
3731
- // ----- Change the file status
3732
- $p_entry['status'] = "already_a_directory";
3733
-
3734
- // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3735
- // For historical reason first PclZip implementation does not stop
3736
- // when this kind of error occurs.
3737
- if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
3738
- && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
3739
-
3740
- PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY,
3741
- "Filename '".$p_entry['filename']."' is "
3742
- ."already used by an existing directory");
3743
-
3744
- return PclZip::errorCode();
3745
- }
3746
- }
3747
- // ----- Look if file is write protected
3748
- else if (!is_writeable($p_entry['filename']))
3749
- {
3750
-
3751
- // ----- Change the file status
3752
- $p_entry['status'] = "write_protected";
3753
-
3754
- // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3755
- // For historical reason first PclZip implementation does not stop
3756
- // when this kind of error occurs.
3757
- if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
3758
- && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
3759
-
3760
- PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
3761
- "Filename '".$p_entry['filename']."' exists "
3762
- ."and is write protected");
3763
-
3764
- return PclZip::errorCode();
3765
- }
3766
- }
3767
-
3768
- // ----- Look if the extracted file is older
3769
- else if (filemtime($p_entry['filename']) > $p_entry['mtime'])
3770
- {
3771
- // ----- Change the file status
3772
- if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER]))
3773
- && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) {
3774
- }
3775
- else {
3776
- $p_entry['status'] = "newer_exist";
3777
-
3778
- // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3779
- // For historical reason first PclZip implementation does not stop
3780
- // when this kind of error occurs.
3781
- if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
3782
- && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
3783
-
3784
- PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
3785
- "Newer version of '".$p_entry['filename']."' exists "
3786
- ."and option PCLZIP_OPT_REPLACE_NEWER is not selected");
3787
-
3788
- return PclZip::errorCode();
3789
- }
3790
- }
3791
- }
3792
- else {
3793
- }
3794
- }
3795
-
3796
- // ----- Check the directory availability and create it if necessary
3797
- else {
3798
- if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/'))
3799
- $v_dir_to_check = $p_entry['filename'];
3800
- else if (!strstr($p_entry['filename'], "/"))
3801
- $v_dir_to_check = "";
3802
- else
3803
- $v_dir_to_check = dirname($p_entry['filename']);
3804
-
3805
- if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) {
3806
-
3807
- // ----- Change the file status
3808
- $p_entry['status'] = "path_creation_fail";
3809
-
3810
- // ----- Return
3811
- //return $v_result;
3812
- $v_result = 1;
3813
- }
3814
- }
3815
- }
3816
-
3817
- // ----- Look if extraction should be done
3818
- if ($p_entry['status'] == 'ok') {
3819
-
3820
- // ----- Do the extraction (if not a folder)
3821
- if (!(($p_entry['external']&0x00000010)==0x00000010))
3822
- {
3823
- // ----- Look for not compressed file
3824
- if ($p_entry['compression'] == 0) {
3825
-
3826
- // ----- Opening destination file
3827
- if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0)
3828
- {
3829
-
3830
- // ----- Change the file status
3831
- $p_entry['status'] = "write_error";
3832
-
3833
- // ----- Return
3834
- return $v_result;
3835
- }
3836
-
3837
-
3838
- // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
3839
- $v_size = $p_entry['compressed_size'];
3840
- while ($v_size != 0)
3841
- {
3842
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
3843
- $v_buffer = @fread($this->zip_fd, $v_read_size);
3844
- /* Try to speed up the code
3845
- $v_binary_data = pack('a'.$v_read_size, $v_buffer);
3846
- @fwrite($v_dest_file, $v_binary_data, $v_read_size);
3847
- */
3848
- @fwrite($v_dest_file, $v_buffer, $v_read_size);
3849
- $v_size -= $v_read_size;
3850
- }
3851
-
3852
- // ----- Closing the destination file
3853
- fclose($v_dest_file);
3854
-
3855
- // ----- Change the file mtime
3856
- touch($p_entry['filename'], $p_entry['mtime']);
3857
-
3858
-
3859
- }
3860
- else {
3861
- // ----- TBC
3862
- // Need to be finished
3863
- if (($p_entry['flag'] & 1) == 1) {
3864
- PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.');
3865
- return PclZip::errorCode();
3866
- }
3867
-
3868
-
3869
- // ----- Look for using temporary file to unzip
3870
- if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
3871
- && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
3872
- || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
3873
- && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) {
3874
- $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
3875
- if ($v_result < PCLZIP_ERR_NO_ERROR) {
3876
- return $v_result;
3877
- }
3878
- }
3879
-
3880
- // ----- Look for extract in memory
3881
- else {
3882
-
3883
-
3884
- // ----- Read the compressed file in a buffer (one shot)
3885
- $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
3886
-
3887
- // ----- Decompress the file
3888
- $v_file_content = @gzinflate($v_buffer);
3889
- unset($v_buffer);
3890
- if ($v_file_content === FALSE) {
3891
-
3892
- // ----- Change the file status
3893
- // TBC
3894
- $p_entry['status'] = "error";
3895
-
3896
- return $v_result;
3897
- }
3898
-
3899
- // ----- Opening destination file
3900
- if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
3901
-
3902
- // ----- Change the file status
3903
- $p_entry['status'] = "write_error";
3904
-
3905
- return $v_result;
3906
- }
3907
-
3908
- // ----- Write the uncompressed data
3909
- @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
3910
- unset($v_file_content);
3911
-
3912
- // ----- Closing the destination file
3913
- @fclose($v_dest_file);
3914
-
3915
- }
3916
-
3917
- // ----- Change the file mtime
3918
- @touch($p_entry['filename'], $p_entry['mtime']);
3919
- }
3920
-
3921
- // ----- Look for chmod option
3922
- if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
3923
-
3924
- // ----- Change the mode of the file
3925
- @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
3926
- }
3927
-
3928
- }
3929
- }
3930
-
3931
- // ----- Change abort status
3932
- if ($p_entry['status'] == "aborted") {
3933
- $p_entry['status'] = "skipped";
3934
- }
3935
-
3936
- // ----- Look for post-extract callback
3937
- elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
3938
-
3939
- // ----- Generate a local information
3940
- $v_local_header = array();
3941
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
3942
-
3943
- // ----- Call the callback
3944
- // Here I do not use call_user_func() because I need to send a reference to the
3945
- // header.
3946
- // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
3947
- $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
3948
-
3949
- // ----- Look for abort result
3950
- if ($v_result == 2) {
3951
- $v_result = PCLZIP_ERR_USER_ABORTED;
3952
- }
3953
- }
3954
-
3955
- // ----- Return
3956
- return $v_result;
3957
- }
3958
- // --------------------------------------------------------------------------------
3959
-
3960
- // --------------------------------------------------------------------------------
3961
- // Function : privExtractFileUsingTempFile()
3962
- // Description :
3963
- // Parameters :
3964
- // Return Values :
3965
- // --------------------------------------------------------------------------------
3966
- function privExtractFileUsingTempFile(&$p_entry, &$p_options)
3967
- {
3968
- $v_result=1;
3969
-
3970
- // ----- Creates a temporary file
3971
- $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
3972
- if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
3973
- fclose($v_file);
3974
- PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
3975
- return PclZip::errorCode();
3976
- }
3977
-
3978
-
3979
- // ----- Write gz file format header
3980
- $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
3981
- @fwrite($v_dest_file, $v_binary_data, 10);
3982
-
3983
- // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
3984
- $v_size = $p_entry['compressed_size'];
3985
- while ($v_size != 0)
3986
- {
3987
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
3988
- $v_buffer = @fread($this->zip_fd, $v_read_size);
3989
- //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
3990
- @fwrite($v_dest_file, $v_buffer, $v_read_size);
3991
- $v_size -= $v_read_size;
3992
- }
3993
-
3994
- // ----- Write gz file format footer
3995
- $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
3996
- @fwrite($v_dest_file, $v_binary_data, 8);
3997
-
3998
- // ----- Close the temporary file
3999
- @fclose($v_dest_file);
4000
-
4001
- // ----- Opening destination file
4002
- if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
4003
- $p_entry['status'] = "write_error";
4004
- return $v_result;
4005
- }
4006
-
4007
- // ----- Open the temporary gz file
4008
- if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {
4009
- @fclose($v_dest_file);
4010
- $p_entry['status'] = "read_error";
4011
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
4012
- return PclZip::errorCode();
4013
- }
4014
-
4015
-
4016
- // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
4017
- $v_size = $p_entry['size'];
4018
- while ($v_size != 0) {
4019
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
4020
- $v_buffer = @gzread($v_src_file, $v_read_size);
4021
- //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
4022
- @fwrite($v_dest_file, $v_buffer, $v_read_size);
4023
- $v_size -= $v_read_size;
4024
- }
4025
- @fclose($v_dest_file);
4026
- @gzclose($v_src_file);
4027
-
4028
- // ----- Delete the temporary file
4029
- @unlink($v_gzip_temp_name);
4030
-
4031
- // ----- Return
4032
- return $v_result;
4033
- }
4034
- // --------------------------------------------------------------------------------
4035
-
4036
- // --------------------------------------------------------------------------------
4037
- // Function : privExtractFileInOutput()
4038
- // Description :
4039
- // Parameters :
4040
- // Return Values :
4041
- // --------------------------------------------------------------------------------
4042
- function privExtractFileInOutput(&$p_entry, &$p_options)
4043
- {
4044
- $v_result=1;
4045
-
4046
- // ----- Read the file header
4047
- if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
4048
- return $v_result;
4049
- }
4050
-
4051
-
4052
- // ----- Check that the file header is coherent with $p_entry info
4053
- if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
4054
- // TBC
4055
- }
4056
-
4057
- // ----- Look for pre-extract callback
4058
- if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
4059
-
4060
- // ----- Generate a local information
4061
- $v_local_header = array();
4062
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
4063
-
4064
- // ----- Call the callback
4065
- // Here I do not use call_user_func() because I need to send a reference to the
4066
- // header.
4067
- // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
4068
- $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
4069
- if ($v_result == 0) {
4070
- // ----- Change the file status
4071
- $p_entry['status'] = "skipped";
4072
- $v_result = 1;
4073
- }
4074
-
4075
- // ----- Look for abort result
4076
- if ($v_result == 2) {
4077
- // ----- This status is internal and will be changed in 'skipped'
4078
- $p_entry['status'] = "aborted";
4079
- $v_result = PCLZIP_ERR_USER_ABORTED;
4080
- }
4081
-
4082
- // ----- Update the informations
4083
- // Only some fields can be modified
4084
- $p_entry['filename'] = $v_local_header['filename'];
4085
- }
4086
-
4087
- // ----- Trace
4088
-
4089
- // ----- Look if extraction should be done
4090
- if ($p_entry['status'] == 'ok') {
4091
-
4092
- // ----- Do the extraction (if not a folder)
4093
- if (!(($p_entry['external']&0x00000010)==0x00000010)) {
4094
- // ----- Look for not compressed file
4095
- if ($p_entry['compressed_size'] == $p_entry['size']) {
4096
-
4097
- // ----- Read the file in a buffer (one shot)
4098
- $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
4099
-
4100
- // ----- Send the file to the output
4101
- echo $v_buffer;
4102
- unset($v_buffer);
4103
- }
4104
- else {
4105
-
4106
- // ----- Read the compressed file in a buffer (one shot)
4107
- $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
4108
-
4109
- // ----- Decompress the file
4110
- $v_file_content = gzinflate($v_buffer);
4111
- unset($v_buffer);
4112
-
4113
- // ----- Send the file to the output
4114
- echo $v_file_content;
4115
- unset($v_file_content);
4116
- }
4117
- }
4118
- }
4119
-
4120
- // ----- Change abort status
4121
- if ($p_entry['status'] == "aborted") {
4122
- $p_entry['status'] = "skipped";
4123
- }
4124
-
4125
- // ----- Look for post-extract callback
4126
- elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
4127
-
4128
- // ----- Generate a local information
4129
- $v_local_header = array();
4130
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
4131
-
4132
- // ----- Call the callback
4133
- // Here I do not use call_user_func() because I need to send a reference to the
4134
- // header.
4135
- // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
4136
- $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
4137
-
4138
- // ----- Look for abort result
4139
- if ($v_result == 2) {
4140
- $v_result = PCLZIP_ERR_USER_ABORTED;
4141
- }
4142
- }
4143
-
4144
- return $v_result;
4145
- }
4146
- // --------------------------------------------------------------------------------
4147
-
4148
- // --------------------------------------------------------------------------------
4149
- // Function : privExtractFileAsString()
4150
- // Description :
4151
- // Parameters :
4152
- // Return Values :
4153
- // --------------------------------------------------------------------------------
4154
- function privExtractFileAsString(&$p_entry, &$p_string, &$p_options)
4155
- {
4156
- $v_result=1;
4157
-
4158
- // ----- Read the file header
4159
- $v_header = array();
4160
- if (($v_result = $this->privReadFileHeader($v_header)) != 1)
4161
- {
4162
- // ----- Return
4163
- return $v_result;
4164
- }
4165
-
4166
-
4167
- // ----- Check that the file header is coherent with $p_entry info
4168
- if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
4169
- // TBC
4170
- }
4171
-
4172
- // ----- Look for pre-extract callback
4173
- if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
4174
-
4175
- // ----- Generate a local information
4176
- $v_local_header = array();
4177
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
4178
-
4179
- // ----- Call the callback
4180
- // Here I do not use call_user_func() because I need to send a reference to the
4181
- // header.
4182
- // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
4183
- $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
4184
- if ($v_result == 0) {
4185
- // ----- Change the file status
4186
- $p_entry['status'] = "skipped";
4187
- $v_result = 1;
4188
- }
4189
-
4190
- // ----- Look for abort result
4191
- if ($v_result == 2) {
4192
- // ----- This status is internal and will be changed in 'skipped'
4193
- $p_entry['status'] = "aborted";
4194
- $v_result = PCLZIP_ERR_USER_ABORTED;
4195
- }
4196
-
4197
- // ----- Update the informations
4198
- // Only some fields can be modified
4199
- $p_entry['filename'] = $v_local_header['filename'];
4200
- }
4201
-
4202
-
4203
- // ----- Look if extraction should be done
4204
- if ($p_entry['status'] == 'ok') {
4205
-
4206
- // ----- Do the extraction (if not a folder)
4207
- if (!(($p_entry['external']&0x00000010)==0x00000010)) {
4208
- // ----- Look for not compressed file
4209
- // if ($p_entry['compressed_size'] == $p_entry['size'])
4210
- if ($p_entry['compression'] == 0) {
4211
-
4212
- // ----- Reading the file
4213
- $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);
4214
- }
4215
- else {
4216
-
4217
- // ----- Reading the file
4218
- $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);
4219
-
4220
- // ----- Decompress the file
4221
- if (($p_string = @gzinflate($v_data)) === FALSE) {
4222
- // TBC
4223
- }
4224
- }
4225
-
4226
- // ----- Trace
4227
- }
4228
- else {
4229
- // TBC : error : can not extract a folder in a string
4230
- }
4231
-
4232
- }
4233
-
4234
- // ----- Change abort status
4235
- if ($p_entry['status'] == "aborted") {
4236
- $p_entry['status'] = "skipped";
4237
- }
4238
-
4239
- // ----- Look for post-extract callback
4240
- elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
4241
-
4242
- // ----- Generate a local information
4243
- $v_local_header = array();
4244
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
4245
-
4246
- // ----- Swap the content to header
4247
- $v_local_header['content'] = $p_string;
4248
- $p_string = '';
4249
-
4250
- // ----- Call the callback
4251
- // Here I do not use call_user_func() because I need to send a reference to the
4252
- // header.
4253
- // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
4254
- $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
4255
-
4256
- // ----- Swap back the content to header
4257
- $p_string = $v_local_header['content'];
4258
- unset($v_local_header['content']);
4259
-
4260
- // ----- Look for abort result
4261
- if ($v_result == 2) {
4262
- $v_result = PCLZIP_ERR_USER_ABORTED;
4263
- }
4264
- }
4265
-
4266
- // ----- Return
4267
- return $v_result;
4268
- }
4269
- // --------------------------------------------------------------------------------
4270
-
4271
- // --------------------------------------------------------------------------------
4272
- // Function : privReadFileHeader()
4273
- // Description :
4274
- // Parameters :
4275
- // Return Values :
4276
- // --------------------------------------------------------------------------------
4277
- function privReadFileHeader(&$p_header)
4278
- {
4279
- $v_result=1;
4280
-
4281
- // ----- Read the 4 bytes signature
4282
- $v_binary_data = @fread($this->zip_fd, 4);
4283
- $v_data = unpack('Vid', $v_binary_data);
4284
-
4285
- // ----- Check signature
4286
- if ($v_data['id'] != 0x04034b50)
4287
- {
4288
-
4289
- // ----- Error log
4290
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
4291
-
4292
- // ----- Return
4293
- return PclZip::errorCode();
4294
- }
4295
-
4296
- // ----- Read the first 42 bytes of the header
4297
- $v_binary_data = fread($this->zip_fd, 26);
4298
-
4299
- // ----- Look for invalid block size
4300
- if (strlen($v_binary_data) != 26)
4301
- {
4302
- $p_header['filename'] = "";
4303
- $p_header['status'] = "invalid_header";
4304
-
4305
- // ----- Error log
4306
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
4307
-
4308
- // ----- Return
4309
- return PclZip::errorCode();
4310
- }
4311
-
4312
- // ----- Extract the values
4313
- $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
4314
-
4315
- // ----- Get filename
4316
- $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);
4317
-
4318
- // ----- Get extra_fields
4319
- if ($v_data['extra_len'] != 0) {
4320
- $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);
4321
- }
4322
- else {
4323
- $p_header['extra'] = '';
4324
- }
4325
-
4326
- // ----- Extract properties
4327
- $p_header['version_extracted'] = $v_data['version'];
4328
- $p_header['compression'] = $v_data['compression'];
4329
- $p_header['size'] = $v_data['size'];
4330
- $p_header['compressed_size'] = $v_data['compressed_size'];
4331
- $p_header['crc'] = $v_data['crc'];
4332
- $p_header['flag'] = $v_data['flag'];
4333
- $p_header['filename_len'] = $v_data['filename_len'];
4334
-
4335
- // ----- Recuperate date in UNIX format
4336
- $p_header['mdate'] = $v_data['mdate'];
4337
- $p_header['mtime'] = $v_data['mtime'];
4338
- if ($p_header['mdate'] && $p_header['mtime'])
4339
- {
4340
- // ----- Extract time
4341
- $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
4342
- $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
4343
- $v_seconde = ($p_header['mtime'] & 0x001F)*2;
4344
-
4345
- // ----- Extract date
4346
- $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
4347
- $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
4348
- $v_day = $p_header['mdate'] & 0x001F;
4349
-
4350
- // ----- Get UNIX date format
4351
- $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
4352
-
4353
- }
4354
- else
4355
- {
4356
- $p_header['mtime'] = time();
4357
- }
4358
-
4359
- // TBC
4360
- //for(reset($v_data); $key = key($v_data); next($v_data)) {
4361
- //}
4362
-
4363
- // ----- Set the stored filename
4364
- $p_header['stored_filename'] = $p_header['filename'];
4365
-
4366
- // ----- Set the status field
4367
- $p_header['status'] = "ok";
4368
-
4369
- // ----- Return
4370
- return $v_result;
4371
- }
4372
- // --------------------------------------------------------------------------------
4373
-
4374
- // --------------------------------------------------------------------------------
4375
- // Function : privReadCentralFileHeader()
4376
- // Description :
4377
- // Parameters :
4378
- // Return Values :
4379
- // --------------------------------------------------------------------------------
4380
- function privReadCentralFileHeader(&$p_header)
4381
- {
4382
- $v_result=1;
4383
-
4384
- // ----- Read the 4 bytes signature
4385
- $v_binary_data = @fread($this->zip_fd, 4);
4386
- $v_data = unpack('Vid', $v_binary_data);
4387
-
4388
- // ----- Check signature
4389
- if ($v_data['id'] != 0x02014b50)
4390
- {
4391
-
4392
- // ----- Error log
4393
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
4394
-
4395
- // ----- Return
4396
- return PclZip::errorCode();
4397
- }
4398
-
4399
- // ----- Read the first 42 bytes of the header
4400
- $v_binary_data = fread($this->zip_fd, 42);
4401
-
4402
- // ----- Look for invalid block size
4403
- if (strlen($v_binary_data) != 42)
4404
- {
4405
- $p_header['filename'] = "";
4406
- $p_header['status'] = "invalid_header";
4407
-
4408
- // ----- Error log
4409
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
4410
-
4411
- // ----- Return
4412
- return PclZip::errorCode();
4413
- }
4414
-
4415
- // ----- Extract the values
4416
- $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data);
4417
-
4418
- // ----- Get filename
4419
- if ($p_header['filename_len'] != 0)
4420
- $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);
4421
- else
4422
- $p_header['filename'] = '';
4423
-
4424
- // ----- Get extra
4425
- if ($p_header['extra_len'] != 0)
4426
- $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);
4427
- else
4428
- $p_header['extra'] = '';
4429
-
4430
- // ----- Get comment
4431
- if ($p_header['comment_len'] != 0)
4432
- $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);
4433
- else
4434
- $p_header['comment'] = '';
4435
-
4436
- // ----- Extract properties
4437
-
4438
- // ----- Recuperate date in UNIX format
4439
- //if ($p_header['mdate'] && $p_header['mtime'])
4440
- // TBC : bug : this was ignoring time with 0/0/0
4441
- if (1)
4442
- {
4443
- // ----- Extract time
4444
- $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
4445
- $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
4446
- $v_seconde = ($p_header['mtime'] & 0x001F)*2;
4447
-
4448
- // ----- Extract date
4449
- $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
4450
- $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
4451
- $v_day = $p_header['mdate'] & 0x001F;
4452
-
4453
- // ----- Get UNIX date format
4454
- $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
4455
-
4456
- }
4457
- else
4458
- {
4459
- $p_header['mtime'] = time();
4460
- }
4461
-
4462
- // ----- Set the stored filename
4463
- $p_header['stored_filename'] = $p_header['filename'];
4464
-
4465
- // ----- Set default status to ok
4466
- $p_header['status'] = 'ok';
4467
-
4468
- // ----- Look if it is a directory
4469
- if (substr($p_header['filename'], -1) == '/') {
4470
- //$p_header['external'] = 0x41FF0010;
4471
- $p_header['external'] = 0x00000010;
4472
- }
4473
-
4474
-
4475
- // ----- Return
4476
- return $v_result;
4477
- }
4478
- // --------------------------------------------------------------------------------
4479
-
4480
- // --------------------------------------------------------------------------------
4481
- // Function : privCheckFileHeaders()
4482
- // Description :
4483
- // Parameters :
4484
- // Return Values :
4485
- // 1 on success,
4486
- // 0 on error;
4487
- // --------------------------------------------------------------------------------
4488
- function privCheckFileHeaders(&$p_local_header, &$p_central_header)
4489
- {
4490
- $v_result=1;
4491
-
4492
- // ----- Check the static values
4493
- // TBC
4494
- if ($p_local_header['filename'] != $p_central_header['filename']) {
4495
- }
4496
- if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {
4497
- }
4498
- if ($p_local_header['flag'] != $p_central_header['flag']) {
4499
- }
4500
- if ($p_local_header['compression'] != $p_central_header['compression']) {
4501
- }
4502
- if ($p_local_header['mtime'] != $p_central_header['mtime']) {
4503
- }
4504
- if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {
4505
- }
4506
-
4507
- // ----- Look for flag bit 3
4508
- if (($p_local_header['flag'] & 8) == 8) {
4509
- $p_local_header['size'] = $p_central_header['size'];
4510
- $p_local_header['compressed_size'] = $p_central_header['compressed_size'];
4511
- $p_local_header['crc'] = $p_central_header['crc'];
4512
- }
4513
-
4514
- // ----- Return
4515
- return $v_result;
4516
- }
4517
- // --------------------------------------------------------------------------------
4518
-
4519
- // --------------------------------------------------------------------------------
4520
- // Function : privReadEndCentralDir()
4521
- // Description :
4522
- // Parameters :
4523
- // Return Values :
4524
- // --------------------------------------------------------------------------------
4525
- function privReadEndCentralDir(&$p_central_dir)
4526
- {
4527
- $v_result=1;
4528
-
4529
- // ----- Go to the end of the zip file
4530
- $v_size = filesize($this->zipname);
4531
- @fseek($this->zip_fd, $v_size);
4532
- if (@ftell($this->zip_fd) != $v_size)
4533
- {
4534
- // ----- Error log
4535
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\'');
4536
-
4537
- // ----- Return
4538
- return PclZip::errorCode();
4539
- }
4540
-
4541
- // ----- First try : look if this is an archive with no commentaries (most of the time)
4542
- // in this case the end of central dir is at 22 bytes of the file end
4543
- $v_found = 0;
4544
- if ($v_size > 26) {
4545
- @fseek($this->zip_fd, $v_size-22);
4546
- if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22))
4547
- {
4548
- // ----- Error log
4549
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
4550
-
4551
- // ----- Return
4552
- return PclZip::errorCode();
4553
- }
4554
-
4555
- // ----- Read for bytes
4556
- $v_binary_data = @fread($this->zip_fd, 4);
4557
- $v_data = @unpack('Vid', $v_binary_data);
4558
-
4559
- // ----- Check signature
4560
- if ($v_data['id'] == 0x06054b50) {
4561
- $v_found = 1;
4562
- }
4563
-
4564
- $v_pos = ftell($this->zip_fd);
4565
- }
4566
-
4567
- // ----- Go back to the maximum possible size of the Central Dir End Record
4568
- if (!$v_found) {
4569
- $v_maximum_size = 65557; // 0xFFFF + 22;
4570
- if ($v_maximum_size > $v_size)
4571
- $v_maximum_size = $v_size;
4572
- @fseek($this->zip_fd, $v_size-$v_maximum_size);
4573
- if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size))
4574
- {
4575
- // ----- Error log
4576
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
4577
-
4578
- // ----- Return
4579
- return PclZip::errorCode();
4580
- }
4581
-
4582
- // ----- Read byte per byte in order to find the signature
4583
- $v_pos = ftell($this->zip_fd);
4584
- $v_bytes = 0x00000000;
4585
- while ($v_pos < $v_size)
4586
- {
4587
- // ----- Read a byte
4588
- $v_byte = @fread($this->zip_fd, 1);
4589
-
4590
- // ----- Add the byte
4591
- //$v_bytes = ($v_bytes << 8) | Ord($v_byte);
4592
- // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number
4593
- // Otherwise on systems where we have 64bit integers the check below for the magic number will fail.
4594
- $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte);
4595
-
4596
- // ----- Compare the bytes
4597
- if ($v_bytes == 0x504b0506)
4598
- {
4599
- $v_pos++;
4600
- break;
4601
- }
4602
-
4603
- $v_pos++;
4604
- }
4605
-
4606
- // ----- Look if not found end of central dir
4607
- if ($v_pos == $v_size)
4608
- {
4609
-
4610
- // ----- Error log
4611
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature");
4612
-
4613
- // ----- Return
4614
- return PclZip::errorCode();
4615
- }
4616
- }
4617
-
4618
- // ----- Read the first 18 bytes of the header
4619
- $v_binary_data = fread($this->zip_fd, 18);
4620
-
4621
- // ----- Look for invalid block size
4622
- if (strlen($v_binary_data) != 18)
4623
- {
4624
-
4625
- // ----- Error log
4626
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data));
4627
-
4628
- // ----- Return
4629
- return PclZip::errorCode();
4630
- }
4631
-
4632
- // ----- Extract the values
4633
- $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
4634
-
4635
- // ----- Check the global size
4636
- if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
4637
-
4638
- // ----- Removed in release 2.2 see readme file
4639
- // The check of the file size is a little too strict.
4640
- // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.
4641
- // While decrypted, zip has training 0 bytes
4642
- if (0) {
4643
- // ----- Error log
4644
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
4645
- 'The central dir is not at the end of the archive.'
4646
- .' Some trailing bytes exists after the archive.');
4647
-
4648
- // ----- Return
4649
- return PclZip::errorCode();
4650
- }
4651
- }
4652
-
4653
- // ----- Get comment
4654
- if ($v_data['comment_size'] != 0) {
4655
- $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);
4656
- }
4657
- else
4658
- $p_central_dir['comment'] = '';
4659
-
4660
- $p_central_dir['entries'] = $v_data['entries'];
4661
- $p_central_dir['disk_entries'] = $v_data['disk_entries'];
4662
- $p_central_dir['offset'] = $v_data['offset'];
4663
- $p_central_dir['size'] = $v_data['size'];
4664
- $p_central_dir['disk'] = $v_data['disk'];
4665
- $p_central_dir['disk_start'] = $v_data['disk_start'];
4666
-
4667
- // TBC
4668
- //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) {
4669
- //}
4670
-
4671
- // ----- Return
4672
- return $v_result;
4673
- }
4674
- // --------------------------------------------------------------------------------
4675
-
4676
- // --------------------------------------------------------------------------------
4677
- // Function : privDeleteByRule()
4678
- // Description :
4679
- // Parameters :
4680
- // Return Values :
4681
- // --------------------------------------------------------------------------------
4682
- function privDeleteByRule(&$p_result_list, &$p_options)
4683
- {
4684
- $v_result=1;
4685
- $v_list_detail = array();
4686
-
4687
- // ----- Open the zip file
4688
- if (($v_result=$this->privOpenFd('rb')) != 1)
4689
- {
4690
- // ----- Return
4691
- return $v_result;
4692
- }
4693
-
4694
- // ----- Read the central directory informations
4695
- $v_central_dir = array();
4696
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
4697
- {
4698
- $this->privCloseFd();
4699
- return $v_result;
4700
- }
4701
-
4702
- // ----- Go to beginning of File
4703
- @rewind($this->zip_fd);
4704
-
4705
- // ----- Scan all the files
4706
- // ----- Start at beginning of Central Dir
4707
- $v_pos_entry = $v_central_dir['offset'];
4708
- @rewind($this->zip_fd);
4709
- if (@fseek($this->zip_fd, $v_pos_entry))
4710
- {
4711
- // ----- Close the zip file
4712
- $this->privCloseFd();
4713
-
4714
- // ----- Error log
4715
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
4716
-
4717
- // ----- Return
4718
- return PclZip::errorCode();
4719
- }
4720
-
4721
- // ----- Read each entry
4722
- $v_header_list = array();
4723
- $j_start = 0;
4724
- for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
4725
- {
4726
-
4727
- // ----- Read the file header
4728
- $v_header_list[$v_nb_extracted] = array();
4729
- if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1)
4730
- {
4731
- // ----- Close the zip file
4732
- $this->privCloseFd();
4733
-
4734
- return $v_result;
4735
- }
4736
-
4737
-
4738
- // ----- Store the index
4739
- $v_header_list[$v_nb_extracted]['index'] = $i;
4740
-
4741
- // ----- Look for the specific extract rules
4742
- $v_found = false;
4743
-
4744
- // ----- Look for extract by name rule
4745
- if ( (isset($p_options[PCLZIP_OPT_BY_NAME]))
4746
- && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
4747
-
4748
- // ----- Look if the filename is in the list
4749
- for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) {
4750
-
4751
- // ----- Look for a directory
4752
- if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
4753
-
4754
- // ----- Look if the directory is in the filename path
4755
- if ( (strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
4756
- && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
4757
- $v_found = true;
4758
- }
4759
- elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */
4760
- && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
4761
- $v_found = true;
4762
- }
4763
- }
4764
- // ----- Look for a filename
4765
- elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
4766
- $v_found = true;
4767
- }
4768
- }
4769
- }
4770
-
4771
- // ----- Look for extract by ereg rule
4772
- // ereg() is deprecated with PHP 5.3
4773
- /*
4774
- else if ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
4775
- && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
4776
-
4777
- if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
4778
- $v_found = true;
4779
- }
4780
- }
4781
- */
4782
-
4783
- // ----- Look for extract by preg rule
4784
- else if ( (isset($p_options[PCLZIP_OPT_BY_PREG]))
4785
- && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
4786
-
4787
- if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
4788
- $v_found = true;
4789
- }
4790
- }
4791
-
4792
- // ----- Look for extract by index rule
4793
- else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX]))
4794
- && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
4795
-
4796
- // ----- Look if the index is in the list
4797
- for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) {
4798
-
4799
- if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
4800
- $v_found = true;
4801
- }
4802
- if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
4803
- $j_start = $j+1;
4804
- }
4805
-
4806
- if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
4807
- break;
4808
- }
4809
- }
4810
- }
4811
- else {
4812
- $v_found = true;
4813
- }
4814
-
4815
- // ----- Look for deletion
4816
- if ($v_found)
4817
- {
4818
- unset($v_header_list[$v_nb_extracted]);
4819
- }
4820
- else
4821
- {
4822
- $v_nb_extracted++;
4823
- }
4824
- }
4825
-
4826
- // ----- Look if something need to be deleted
4827
- if ($v_nb_extracted > 0) {
4828
-
4829
- // ----- Creates a temporay file
4830
- $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
4831
-
4832
- // ----- Creates a temporary zip archive
4833
- $v_temp_zip = new PclZip($v_zip_temp_name);
4834
-
4835
- // ----- Open the temporary zip file in write mode
4836
- if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) {
4837
- $this->privCloseFd();
4838
-
4839
- // ----- Return
4840
- return $v_result;
4841
- }
4842
-
4843
- // ----- Look which file need to be kept
4844
- for ($i=0; $i<sizeof($v_header_list); $i++) {
4845
-
4846
- // ----- Calculate the position of the header
4847
- @rewind($this->zip_fd);
4848
- if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) {
4849
- // ----- Close the zip file
4850
- $this->privCloseFd();
4851
- $v_temp_zip->privCloseFd();
4852
- @unlink($v_zip_temp_name);
4853
-
4854
- // ----- Error log
4855
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
4856
-
4857
- // ----- Return
4858
- return PclZip::errorCode();
4859
- }
4860
-
4861
- // ----- Read the file header
4862
- $v_local_header = array();
4863
- if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) {
4864
- // ----- Close the zip file
4865
- $this->privCloseFd();
4866
- $v_temp_zip->privCloseFd();
4867
- @unlink($v_zip_temp_name);
4868
-
4869
- // ----- Return
4870
- return $v_result;
4871
- }
4872
-
4873
- // ----- Check that local file header is same as central file header
4874
- if ($this->privCheckFileHeaders($v_local_header,
4875
- $v_header_list[$i]) != 1) {
4876
- // TBC
4877
- }
4878
- unset($v_local_header);
4879
-
4880
- // ----- Write the file header
4881
- if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) {
4882
- // ----- Close the zip file
4883
- $this->privCloseFd();
4884
- $v_temp_zip->privCloseFd();
4885
- @unlink($v_zip_temp_name);
4886
-
4887
- // ----- Return
4888
- return $v_result;
4889
- }
4890
-
4891
- // ----- Read/write the data block
4892
- if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) {
4893
- // ----- Close the zip file
4894
- $this->privCloseFd();
4895
- $v_temp_zip->privCloseFd();
4896
- @unlink($v_zip_temp_name);
4897
-
4898
- // ----- Return
4899
- return $v_result;
4900
- }
4901
- }
4902
-
4903
- // ----- Store the offset of the central dir
4904
- $v_offset = @ftell($v_temp_zip->zip_fd);
4905
-
4906
- // ----- Re-Create the Central Dir files header
4907
- for ($i=0; $i<sizeof($v_header_list); $i++) {
4908
- // ----- Create the file header
4909
- if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
4910
- $v_temp_zip->privCloseFd();
4911
- $this->privCloseFd();
4912
- @unlink($v_zip_temp_name);
4913
-
4914
- // ----- Return
4915
- return $v_result;
4916
- }
4917
-
4918
- // ----- Transform the header to a 'usable' info
4919
- $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
4920
- }
4921
-
4922
-
4923
- // ----- Zip file comment
4924
- $v_comment = '';
4925
- if (isset($p_options[PCLZIP_OPT_COMMENT])) {
4926
- $v_comment = $p_options[PCLZIP_OPT_COMMENT];
4927
- }
4928
-
4929
- // ----- Calculate the size of the central header
4930
- $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset;
4931
-
4932
- // ----- Create the central dir footer
4933
- if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) {
4934
- // ----- Reset the file list
4935
- unset($v_header_list);
4936
- $v_temp_zip->privCloseFd();
4937
- $this->privCloseFd();
4938
- @unlink($v_zip_temp_name);
4939
-
4940
- // ----- Return
4941
- return $v_result;
4942
- }
4943
-
4944
- // ----- Close
4945
- $v_temp_zip->privCloseFd();
4946
- $this->privCloseFd();
4947
-
4948
- // ----- Delete the zip file
4949
- // TBC : I should test the result ...
4950
- @unlink($this->zipname);
4951
-
4952
- // ----- Rename the temporary file
4953
- // TBC : I should test the result ...
4954
- //@rename($v_zip_temp_name, $this->zipname);
4955
- PclZipUtilRename($v_zip_temp_name, $this->zipname);
4956
-
4957
- // ----- Destroy the temporary archive
4958
- unset($v_temp_zip);
4959
- }
4960
-
4961
- // ----- Remove every files : reset the file
4962
- else if ($v_central_dir['entries'] != 0) {
4963
- $this->privCloseFd();
4964
-
4965
- if (($v_result = $this->privOpenFd('wb')) != 1) {
4966
- return $v_result;
4967
- }
4968
-
4969
- if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) {
4970
- return $v_result;
4971
- }
4972
-
4973
- $this->privCloseFd();
4974
- }
4975
-
4976
- // ----- Return
4977
- return $v_result;
4978
- }
4979
- // --------------------------------------------------------------------------------
4980
-
4981
- // --------------------------------------------------------------------------------
4982
- // Function : privDirCheck()
4983
- // Description :
4984
- // Check if a directory exists, if not it creates it and all the parents directory
4985
- // which may be useful.
4986
- // Parameters :
4987
- // $p_dir : Directory path to check.
4988
- // Return Values :
4989
- // 1 : OK
4990
- // -1 : Unable to create directory
4991
- // --------------------------------------------------------------------------------
4992
- function privDirCheck($p_dir, $p_is_dir=false)
4993
- {
4994
- $v_result = 1;
4995
-
4996
-
4997
- // ----- Remove the final '/'
4998
- if (($p_is_dir) && (substr($p_dir, -1)=='/'))
4999
- {
5000
- $p_dir = substr($p_dir, 0, strlen($p_dir)-1);
5001
- }
5002
-
5003
- // ----- Check the directory availability
5004
- if ((is_dir($p_dir)) || ($p_dir == ""))
5005
- {
5006
- return 1;
5007
- }
5008
-
5009
- // ----- Extract parent directory
5010
- $p_parent_dir = dirname($p_dir);
5011
-
5012
- // ----- Just a check
5013
- if ($p_parent_dir != $p_dir)
5014
- {
5015
- // ----- Look for parent directory
5016
- if ($p_parent_dir != "")
5017
- {
5018
- if (($v_result = $this->privDirCheck($p_parent_dir)) != 1)
5019
- {
5020
- return $v_result;
5021
- }
5022
- }
5023
- }
5024
-
5025
- // ----- Create the directory
5026
- if (!@mkdir($p_dir, 0777))
5027
- {
5028
- // ----- Error log
5029
- PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
5030
-
5031
- // ----- Return
5032
- return PclZip::errorCode();
5033
- }
5034
-
5035
- // ----- Return
5036
- return $v_result;
5037
- }
5038
- // --------------------------------------------------------------------------------
5039
-
5040
- // --------------------------------------------------------------------------------
5041
- // Function : privMerge()
5042
- // Description :
5043
- // If $p_archive_to_add does not exist, the function exit with a success result.
5044
- // Parameters :
5045
- // Return Values :
5046
- // --------------------------------------------------------------------------------
5047
- function privMerge(&$p_archive_to_add)
5048
- {
5049
- $v_result=1;
5050
-
5051
- // ----- Look if the archive_to_add exists
5052
- if (!is_file($p_archive_to_add->zipname))
5053
- {
5054
-
5055
- // ----- Nothing to merge, so merge is a success
5056
- $v_result = 1;
5057
-
5058
- // ----- Return
5059
- return $v_result;
5060
- }
5061
-
5062
- // ----- Look if the archive exists
5063
- if (!is_file($this->zipname))
5064
- {
5065
-
5066
- // ----- Do a duplicate
5067
- $v_result = $this->privDuplicate($p_archive_to_add->zipname);
5068
-
5069
- // ----- Return
5070
- return $v_result;
5071
- }
5072
-
5073
- // ----- Open the zip file
5074
- if (($v_result=$this->privOpenFd('rb')) != 1)
5075
- {
5076
- // ----- Return
5077
- return $v_result;
5078
- }
5079
-
5080
- // ----- Read the central directory informations
5081
- $v_central_dir = array();
5082
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
5083
- {
5084
- $this->privCloseFd();
5085
- return $v_result;
5086
- }
5087
-
5088
- // ----- Go to beginning of File
5089
- @rewind($this->zip_fd);
5090
-
5091
- // ----- Open the archive_to_add file
5092
- if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1)
5093
- {
5094
- $this->privCloseFd();
5095
-
5096
- // ----- Return
5097
- return $v_result;
5098
- }
5099
-
5100
- // ----- Read the central directory informations
5101
- $v_central_dir_to_add = array();
5102
- if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1)
5103
- {
5104
- $this->privCloseFd();
5105
- $p_archive_to_add->privCloseFd();
5106
-
5107
- return $v_result;
5108
- }
5109
-
5110
- // ----- Go to beginning of File
5111
- @rewind($p_archive_to_add->zip_fd);
5112
-
5113
- // ----- Creates a temporay file
5114
- $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
5115
-
5116
- // ----- Open the temporary file in write mode
5117
- if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
5118
- {
5119
- $this->privCloseFd();
5120
- $p_archive_to_add->privCloseFd();
5121
-
5122
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
5123
-
5124
- // ----- Return
5125
- return PclZip::errorCode();
5126
- }
5127
-
5128
- // ----- Copy the files from the archive to the temporary file
5129
- // TBC : Here I should better append the file and go back to erase the central dir
5130
- $v_size = $v_central_dir['offset'];
5131
- while ($v_size != 0)
5132
- {
5133
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
5134
- $v_buffer = fread($this->zip_fd, $v_read_size);
5135
- @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
5136
- $v_size -= $v_read_size;
5137
- }
5138
-
5139
- // ----- Copy the files from the archive_to_add into the temporary file
5140
- $v_size = $v_central_dir_to_add['offset'];
5141
- while ($v_size != 0)
5142
- {
5143
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
5144
- $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size);
5145
- @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
5146
- $v_size -= $v_read_size;
5147
- }
5148
-
5149
- // ----- Store the offset of the central dir
5150
- $v_offset = @ftell($v_zip_temp_fd);
5151
-
5152
- // ----- Copy the block of file headers from the old archive
5153
- $v_size = $v_central_dir['size'];
5154
- while ($v_size != 0)
5155
- {
5156
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
5157
- $v_buffer = @fread($this->zip_fd, $v_read_size);
5158
- @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
5159
- $v_size -= $v_read_size;
5160
- }
5161
-
5162
- // ----- Copy the block of file headers from the archive_to_add
5163
- $v_size = $v_central_dir_to_add['size'];
5164
- while ($v_size != 0)
5165
- {
5166
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
5167
- $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size);
5168
- @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
5169
- $v_size -= $v_read_size;
5170
- }
5171
-
5172
- // ----- Merge the file comments
5173
- $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment'];
5174
-
5175
- // ----- Calculate the size of the (new) central header
5176
- $v_size = @ftell($v_zip_temp_fd)-$v_offset;
5177
-
5178
- // ----- Swap the file descriptor
5179
- // Here is a trick : I swap the temporary fd with the zip fd, in order to use
5180
- // the following methods on the temporary fil and not the real archive fd
5181
- $v_swap = $this->zip_fd;
5182
- $this->zip_fd = $v_zip_temp_fd;
5183
- $v_zip_temp_fd = $v_swap;
5184
-
5185
- // ----- Create the central dir footer
5186
- if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1)
5187
- {
5188
- $this->privCloseFd();
5189
- $p_archive_to_add->privCloseFd();
5190
- @fclose($v_zip_temp_fd);
5191
- $this->zip_fd = null;
5192
-
5193
- // ----- Reset the file list
5194
- unset($v_header_list);
5195
-
5196
- // ----- Return
5197
- return $v_result;
5198
- }
5199
-
5200
- // ----- Swap back the file descriptor
5201
- $v_swap = $this->zip_fd;
5202
- $this->zip_fd = $v_zip_temp_fd;
5203
- $v_zip_temp_fd = $v_swap;
5204
-
5205
- // ----- Close
5206
- $this->privCloseFd();
5207
- $p_archive_to_add->privCloseFd();
5208
-
5209
- // ----- Close the temporary file
5210
- @fclose($v_zip_temp_fd);
5211
-
5212
- // ----- Delete the zip file
5213
- // TBC : I should test the result ...
5214
- @unlink($this->zipname);
5215
-
5216
- // ----- Rename the temporary file
5217
- // TBC : I should test the result ...
5218
- //@rename($v_zip_temp_name, $this->zipname);
5219
- PclZipUtilRename($v_zip_temp_name, $this->zipname);
5220
-
5221
- // ----- Return
5222
- return $v_result;
5223
- }
5224
- // --------------------------------------------------------------------------------
5225
-
5226
- // --------------------------------------------------------------------------------
5227
- // Function : privDuplicate()
5228
- // Description :
5229
- // Parameters :
5230
- // Return Values :
5231
- // --------------------------------------------------------------------------------
5232
- function privDuplicate($p_archive_filename)
5233
- {
5234
- $v_result=1;
5235
-
5236
- // ----- Look if the $p_archive_filename exists
5237
- if (!is_file($p_archive_filename))
5238
- {
5239
-
5240
- // ----- Nothing to duplicate, so duplicate is a success.
5241
- $v_result = 1;
5242
-
5243
- // ----- Return
5244
- return $v_result;
5245
- }
5246
-
5247
- // ----- Open the zip file
5248
- if (($v_result=$this->privOpenFd('wb')) != 1)
5249
- {
5250
- // ----- Return
5251
- return $v_result;
5252
- }
5253
-
5254
- // ----- Open the temporary file in write mode
5255
- if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0)
5256
- {
5257
- $this->privCloseFd();
5258
-
5259
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode');
5260
-
5261
- // ----- Return
5262
- return PclZip::errorCode();
5263
- }
5264
-
5265
- // ----- Copy the files from the archive to the temporary file
5266
- // TBC : Here I should better append the file and go back to erase the central dir
5267
- $v_size = filesize($p_archive_filename);
5268
- while ($v_size != 0)
5269
- {
5270
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
5271
- $v_buffer = fread($v_zip_temp_fd, $v_read_size);
5272
- @fwrite($this->zip_fd, $v_buffer, $v_read_size);
5273
- $v_size -= $v_read_size;
5274
- }
5275
-
5276
- // ----- Close
5277
- $this->privCloseFd();
5278
-
5279
- // ----- Close the temporary file
5280
- @fclose($v_zip_temp_fd);
5281
-
5282
- // ----- Return
5283
- return $v_result;
5284
- }
5285
- // --------------------------------------------------------------------------------
5286
-
5287
- // --------------------------------------------------------------------------------
5288
- // Function : privErrorLog()
5289
- // Description :
5290
- // Parameters :
5291
- // --------------------------------------------------------------------------------
5292
- function privErrorLog($p_error_code=0, $p_error_string='')
5293
- {
5294
- if (PCLZIP_ERROR_EXTERNAL == 1) {
5295
- PclError($p_error_code, $p_error_string);
5296
- }
5297
- else {
5298
- $this->error_code = $p_error_code;
5299
- $this->error_string = $p_error_string;
5300
- }
5301
- }
5302
- // --------------------------------------------------------------------------------
5303
-
5304
- // --------------------------------------------------------------------------------
5305
- // Function : privErrorReset()
5306
- // Description :
5307
- // Parameters :
5308
- // --------------------------------------------------------------------------------
5309
- function privErrorReset()
5310
- {
5311
- if (PCLZIP_ERROR_EXTERNAL == 1) {
5312
- PclErrorReset();
5313
- }
5314
- else {
5315
- $this->error_code = 0;
5316
- $this->error_string = '';
5317
- }
5318
- }
5319
- // --------------------------------------------------------------------------------
5320
-
5321
- // --------------------------------------------------------------------------------
5322
- // Function : privDisableMagicQuotes()
5323
- // Description :
5324
- // Parameters :
5325
- // Return Values :
5326
- // --------------------------------------------------------------------------------
5327
- function privDisableMagicQuotes()
5328
- {
5329
- $v_result=1;
5330
-
5331
- // ----- Look if function exists
5332
- if ( (!function_exists("get_magic_quotes_runtime"))
5333
- || (!function_exists("set_magic_quotes_runtime"))) {
5334
- return $v_result;
5335
- }
5336
-
5337
- // ----- Look if already done
5338
- if ($this->magic_quotes_status != -1) {
5339
- return $v_result;
5340
- }
5341
-
5342
- // ----- Get and memorize the magic_quote value
5343
- $this->magic_quotes_status = @get_magic_quotes_runtime();
5344
-
5345
- // ----- Disable magic_quotes
5346
- if ($this->magic_quotes_status == 1) {
5347
- @set_magic_quotes_runtime(0);
5348
- }
5349
-
5350
- // ----- Return
5351
- return $v_result;
5352
- }
5353
- // --------------------------------------------------------------------------------
5354
-
5355
- // --------------------------------------------------------------------------------
5356
- // Function : privSwapBackMagicQuotes()
5357
- // Description :
5358
- // Parameters :
5359
- // Return Values :
5360
- // --------------------------------------------------------------------------------
5361
- function privSwapBackMagicQuotes()
5362
- {
5363
- $v_result=1;
5364
-
5365
- // ----- Look if function exists
5366
- if ( (!function_exists("get_magic_quotes_runtime"))
5367
- || (!function_exists("set_magic_quotes_runtime"))) {
5368
- return $v_result;
5369
- }
5370
-
5371
- // ----- Look if something to do
5372
- if ($this->magic_quotes_status != -1) {
5373
- return $v_result;
5374
- }
5375
-
5376
- // ----- Swap back magic_quotes
5377
- if ($this->magic_quotes_status == 1) {
5378
- @set_magic_quotes_runtime($this->magic_quotes_status);
5379
- }
5380
-
5381
- // ----- Return
5382
- return $v_result;
5383
- }
5384
- // --------------------------------------------------------------------------------
5385
-
5386
- }
5387
- // End of class
5388
- // --------------------------------------------------------------------------------
5389
-
5390
- // --------------------------------------------------------------------------------
5391
- // Function : PclZipUtilPathReduction()
5392
- // Description :
5393
- // Parameters :
5394
- // Return Values :
5395
- // --------------------------------------------------------------------------------
5396
- function PclZipUtilPathReduction($p_dir)
5397
- {
5398
- $v_result = "";
5399
-
5400
- // ----- Look for not empty path
5401
- if ($p_dir != "") {
5402
- // ----- Explode path by directory names
5403
- $v_list = explode("/", $p_dir);
5404
-
5405
- // ----- Study directories from last to first
5406
- $v_skip = 0;
5407
- for ($i=sizeof($v_list)-1; $i>=0; $i--) {
5408
- // ----- Look for current path
5409
- if ($v_list[$i] == ".") {
5410
- // ----- Ignore this directory
5411
- // Should be the first $i=0, but no check is done
5412
- }
5413
- else if ($v_list[$i] == "..") {
5414
- $v_skip++;
5415
- }
5416
- else if ($v_list[$i] == "") {
5417
- // ----- First '/' i.e. root slash
5418
- if ($i == 0) {
5419
- $v_result = "/".$v_result;
5420
- if ($v_skip > 0) {
5421
- // ----- It is an invalid path, so the path is not modified
5422
- // TBC
5423
- $v_result = $p_dir;
5424
- $v_skip = 0;
5425
- }
5426
- }
5427
- // ----- Last '/' i.e. indicates a directory
5428
- else if ($i == (sizeof($v_list)-1)) {
5429
- $v_result = $v_list[$i];
5430
- }
5431
- // ----- Double '/' inside the path
5432
- else {
5433
- // ----- Ignore only the double '//' in path,
5434
- // but not the first and last '/'
5435
- }
5436
- }
5437
- else {
5438
- // ----- Look for item to skip
5439
- if ($v_skip > 0) {
5440
- $v_skip--;
5441
- }
5442
- else {
5443
- $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:"");
5444
- }
5445
- }
5446
- }
5447
-
5448
- // ----- Look for skip
5449
- if ($v_skip > 0) {
5450
- while ($v_skip > 0) {
5451
- $v_result = '../'.$v_result;
5452
- $v_skip--;
5453
- }
5454
- }
5455
- }
5456
-
5457
- // ----- Return
5458
- return $v_result;
5459
- }
5460
- // --------------------------------------------------------------------------------
5461
-
5462
- // --------------------------------------------------------------------------------
5463
- // Function : PclZipUtilPathInclusion()
5464
- // Description :
5465
- // This function indicates if the path $p_path is under the $p_dir tree. Or,
5466
- // said in an other way, if the file or sub-dir $p_path is inside the dir
5467
- // $p_dir.
5468
- // The function indicates also if the path is exactly the same as the dir.
5469
- // This function supports path with duplicated '/' like '//', but does not
5470
- // support '.' or '..' statements.
5471
- // Parameters :
5472
- // Return Values :
5473
- // 0 if $p_path is not inside directory $p_dir
5474
- // 1 if $p_path is inside directory $p_dir
5475
- // 2 if $p_path is exactly the same as $p_dir
5476
- // --------------------------------------------------------------------------------
5477
- function PclZipUtilPathInclusion($p_dir, $p_path)
5478
- {
5479
- $v_result = 1;
5480
-
5481
- // ----- Look for path beginning by ./
5482
- if ( ($p_dir == '.')
5483
- || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) {
5484
- $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1);
5485
- }
5486
- if ( ($p_path == '.')
5487
- || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) {
5488
- $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1);
5489
- }
5490
-
5491
- // ----- Explode dir and path by directory separator
5492
- $v_list_dir = explode("/", $p_dir);
5493
- $v_list_dir_size = sizeof($v_list_dir);
5494
- $v_list_path = explode("/", $p_path);
5495
- $v_list_path_size = sizeof($v_list_path);
5496
-
5497
- // ----- Study directories paths
5498
- $i = 0;
5499
- $j = 0;
5500
- while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {
5501
-
5502
- // ----- Look for empty dir (path reduction)
5503
- if ($v_list_dir[$i] == '') {
5504
- $i++;
5505
- continue;
5506
- }
5507
- if ($v_list_path[$j] == '') {
5508
- $j++;
5509
- continue;
5510
- }
5511
-
5512
- // ----- Compare the items
5513
- if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) {
5514
- $v_result = 0;
5515
- }
5516
-
5517
- // ----- Next items
5518
- $i++;
5519
- $j++;
5520
- }
5521
-
5522
- // ----- Look if everything seems to be the same
5523
- if ($v_result) {
5524
- // ----- Skip all the empty items
5525
- while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++;
5526
- while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++;
5527
-
5528
- if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
5529
- // ----- There are exactly the same
5530
- $v_result = 2;
5531
- }
5532
- else if ($i < $v_list_dir_size) {
5533
- // ----- The path is shorter than the dir
5534
- $v_result = 0;
5535
- }
5536
- }
5537
-
5538
- // ----- Return
5539
- return $v_result;
5540
- }
5541
- // --------------------------------------------------------------------------------
5542
-
5543
- // --------------------------------------------------------------------------------
5544
- // Function : PclZipUtilCopyBlock()
5545
- // Description :
5546
- // Parameters :
5547
- // $p_mode : read/write compression mode
5548
- // 0 : src & dest normal
5549
- // 1 : src gzip, dest normal
5550
- // 2 : src normal, dest gzip
5551
- // 3 : src & dest gzip
5552
- // Return Values :
5553
- // --------------------------------------------------------------------------------
5554
- function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0)
5555
- {
5556
- $v_result = 1;
5557
-
5558
- if ($p_mode==0)
5559
- {
5560
- while ($p_size != 0)
5561
- {
5562
- $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
5563
- $v_buffer = @fread($p_src, $v_read_size);
5564
- @fwrite($p_dest, $v_buffer, $v_read_size);
5565
- $p_size -= $v_read_size;
5566
- }
5567
- }
5568
- else if ($p_mode==1)
5569
- {
5570
- while ($p_size != 0)
5571
- {
5572
- $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
5573
- $v_buffer = @gzread($p_src, $v_read_size);
5574
- @fwrite($p_dest, $v_buffer, $v_read_size);
5575
- $p_size -= $v_read_size;
5576
- }
5577
- }
5578
- else if ($p_mode==2)
5579
- {
5580
- while ($p_size != 0)
5581
- {
5582
- $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
5583
- $v_buffer = @fread($p_src, $v_read_size);
5584
- @gzwrite($p_dest, $v_buffer, $v_read_size);
5585
- $p_size -= $v_read_size;
5586
- }
5587
- }
5588
- else if ($p_mode==3)
5589
- {
5590
- while ($p_size != 0)
5591
- {
5592
- $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
5593
- $v_buffer = @gzread($p_src, $v_read_size);
5594
- @gzwrite($p_dest, $v_buffer, $v_read_size);
5595
- $p_size -= $v_read_size;
5596
- }
5597
- }
5598
-
5599
- // ----- Return
5600
- return $v_result;
5601
- }
5602
- // --------------------------------------------------------------------------------
5603
-
5604
- // --------------------------------------------------------------------------------
5605
- // Function : PclZipUtilRename()
5606
- // Description :
5607
- // This function tries to do a simple rename() function. If it fails, it
5608
- // tries to copy the $p_src file in a new $p_dest file and then unlink the
5609
- // first one.
5610
- // Parameters :
5611
- // $p_src : Old filename
5612
- // $p_dest : New filename
5613
- // Return Values :
5614
- // 1 on success, 0 on failure.
5615
- // --------------------------------------------------------------------------------
5616
- function PclZipUtilRename($p_src, $p_dest)
5617
- {
5618
- $v_result = 1;
5619
-
5620
- // ----- Try to rename the files
5621
- if (!@rename($p_src, $p_dest)) {
5622
-
5623
- // ----- Try to copy & unlink the src
5624
- if (!@copy($p_src, $p_dest)) {
5625
- $v_result = 0;
5626
- }
5627
- else if (!@unlink($p_src)) {
5628
- $v_result = 0;
5629
- }
5630
- }
5631
-
5632
- // ----- Return
5633
- return $v_result;
5634
- }
5635
- // --------------------------------------------------------------------------------
5636
-
5637
- // --------------------------------------------------------------------------------
5638
- // Function : PclZipUtilOptionText()
5639
- // Description :
5640
- // Translate option value in text. Mainly for debug purpose.
5641
- // Parameters :
5642
- // $p_option : the option value.
5643
- // Return Values :
5644
- // The option text value.
5645
- // --------------------------------------------------------------------------------
5646
- function PclZipUtilOptionText($p_option)
5647
- {
5648
-
5649
- $v_list = get_defined_constants();
5650
- for (reset($v_list); $v_key = key($v_list); next($v_list)) {
5651
- $v_prefix = substr($v_key, 0, 10);
5652
- if (( ($v_prefix == 'PCLZIP_OPT')
5653
- || ($v_prefix == 'PCLZIP_CB_')
5654
- || ($v_prefix == 'PCLZIP_ATT'))
5655
- && ($v_list[$v_key] == $p_option)) {
5656
- return $v_key;
5657
- }
5658
- }
5659
-
5660
- $v_result = 'Unknown';
5661
-
5662
- return $v_result;
5663
- }
5664
- // --------------------------------------------------------------------------------
5665
-
5666
- // --------------------------------------------------------------------------------
5667
- // Function : PclZipUtilTranslateWinPath()
5668
- // Description :
5669
- // Translate windows path by replacing '\' by '/' and optionally removing
5670
- // drive letter.
5671
- // Parameters :
5672
- // $p_path : path to translate.
5673
- // $p_remove_disk_letter : true | false
5674
- // Return Values :
5675
- // The path translated.
5676
- // --------------------------------------------------------------------------------
5677
- function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true)
5678
- {
5679
- if (stristr(php_uname(), 'windows')) {
5680
- // ----- Look for potential disk letter
5681
- if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) {
5682
- $p_path = substr($p_path, $v_position+1);
5683
- }
5684
- // ----- Change potential windows directory separator
5685
- if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
5686
- $p_path = strtr($p_path, '\\', '/');
5687
- }
5688
- }
5689
- return $p_path;
5690
- }
5691
- // --------------------------------------------------------------------------------
1
+ <?php
2
+ // --------------------------------------------------------------------------------
3
+ // PhpConcept Library - Zip Module 2.8.2
4
+ // --------------------------------------------------------------------------------
5
+ // License GNU/LGPL - Vincent Blavet - August 2009
6
+ // http://www.phpconcept.net
7
+ // --------------------------------------------------------------------------------
8
+ //
9
+ // Presentation :
10
+ // PclZip is a PHP library that manage ZIP archives.
11
+ // So far tests show that archives generated by PclZip are readable by
12
+ // WinZip application and other tools.
13
+ //
14
+ // Description :
15
+ // See readme.txt and http://www.phpconcept.net
16
+ //
17
+ // Warning :
18
+ // This library and the associated files are non commercial, non professional
19
+ // work.
20
+ // It should not have unexpected results. However if any damage is caused by
21
+ // this software the author can not be responsible.
22
+ // The use of this software is at the risk of the user.
23
+ //
24
+ // --------------------------------------------------------------------------------
25
+ // $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $
26
+ // --------------------------------------------------------------------------------
27
+
28
+ // ----- Constants
29
+ if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
30
+ define( 'PCLZIP_READ_BLOCK_SIZE', 2048 );
31
+ }
32
+
33
+ // ----- File list separator
34
+ // In version 1.x of PclZip, the separator for file list is a space
35
+ // (which is not a very smart choice, specifically for windows paths !).
36
+ // A better separator should be a comma (,). This constant gives you the
37
+ // abilty to change that.
38
+ // However notice that changing this value, may have impact on existing
39
+ // scripts, using space separated filenames.
40
+ // Recommanded values for compatibility with older versions :
41
+ //define( 'PCLZIP_SEPARATOR', ' ' );
42
+ // Recommanded values for smart separation of filenames.
43
+ if (!defined('PCLZIP_SEPARATOR')) {
44
+ define( 'PCLZIP_SEPARATOR', ',' );
45
+ }
46
+
47
+ // ----- Error configuration
48
+ // 0 : PclZip Class integrated error handling
49
+ // 1 : PclError external library error handling. By enabling this
50
+ // you must ensure that you have included PclError library.
51
+ // [2,...] : reserved for futur use
52
+ if (!defined('PCLZIP_ERROR_EXTERNAL')) {
53
+ define( 'PCLZIP_ERROR_EXTERNAL', 0 );
54
+ }
55
+
56
+ // ----- Optional static temporary directory
57
+ // By default temporary files are generated in the script current
58
+ // path.
59
+ // If defined :
60
+ // - MUST BE terminated by a '/'.
61
+ // - MUST be a valid, already created directory
62
+ // Samples :
63
+ // define( 'PCLZIP_TEMPORARY_DIR', '/temp/' );
64
+ // define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' );
65
+ if (!defined('PCLZIP_TEMPORARY_DIR')) {
66
+ define( 'PCLZIP_TEMPORARY_DIR', '' );
67
+ }
68
+
69
+ // ----- Optional threshold ratio for use of temporary files
70
+ // Pclzip sense the size of the file to add/extract and decide to
71
+ // use or not temporary file. The algorythm is looking for
72
+ // memory_limit of PHP and apply a ratio.
73
+ // threshold = memory_limit * ratio.
74
+ // Recommended values are under 0.5. Default 0.47.
75
+ // Samples :
76
+ // define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 );
77
+ if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) {
78
+ define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.47 );
79
+ }
80
+
81
+ // --------------------------------------------------------------------------------
82
+ // ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****
83
+ // --------------------------------------------------------------------------------
84
+
85
+ // ----- Global variables
86
+ $g_pclzip_version = "2.8.2";
87
+
88
+ // ----- Error codes
89
+ // -1 : Unable to open file in binary write mode
90
+ // -2 : Unable to open file in binary read mode
91
+ // -3 : Invalid parameters
92
+ // -4 : File does not exist
93
+ // -5 : Filename is too long (max. 255)
94
+ // -6 : Not a valid zip file
95
+ // -7 : Invalid extracted file size
96
+ // -8 : Unable to create directory
97
+ // -9 : Invalid archive extension
98
+ // -10 : Invalid archive format
99
+ // -11 : Unable to delete file (unlink)
100
+ // -12 : Unable to rename file (rename)
101
+ // -13 : Invalid header checksum
102
+ // -14 : Invalid archive size
103
+ define( 'PCLZIP_ERR_USER_ABORTED', 2 );
104
+ define( 'PCLZIP_ERR_NO_ERROR', 0 );
105
+ define( 'PCLZIP_ERR_WRITE_OPEN_FAIL', -1 );
106
+ define( 'PCLZIP_ERR_READ_OPEN_FAIL', -2 );
107
+ define( 'PCLZIP_ERR_INVALID_PARAMETER', -3 );
108
+ define( 'PCLZIP_ERR_MISSING_FILE', -4 );
109
+ define( 'PCLZIP_ERR_FILENAME_TOO_LONG', -5 );
110
+ define( 'PCLZIP_ERR_INVALID_ZIP', -6 );
111
+ define( 'PCLZIP_ERR_BAD_EXTRACTED_FILE', -7 );
112
+ define( 'PCLZIP_ERR_DIR_CREATE_FAIL', -8 );
113
+ define( 'PCLZIP_ERR_BAD_EXTENSION', -9 );
114
+ define( 'PCLZIP_ERR_BAD_FORMAT', -10 );
115
+ define( 'PCLZIP_ERR_DELETE_FILE_FAIL', -11 );
116
+ define( 'PCLZIP_ERR_RENAME_FILE_FAIL', -12 );
117
+ define( 'PCLZIP_ERR_BAD_CHECKSUM', -13 );
118
+ define( 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14 );
119
+ define( 'PCLZIP_ERR_MISSING_OPTION_VALUE', -15 );
120
+ define( 'PCLZIP_ERR_INVALID_OPTION_VALUE', -16 );
121
+ define( 'PCLZIP_ERR_ALREADY_A_DIRECTORY', -17 );
122
+ define( 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18 );
123
+ define( 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19 );
124
+ define( 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20 );
125
+ define( 'PCLZIP_ERR_DIRECTORY_RESTRICTION', -21 );
126
+
127
+ // ----- Options values
128
+ define( 'PCLZIP_OPT_PATH', 77001 );
129
+ define( 'PCLZIP_OPT_ADD_PATH', 77002 );
130
+ define( 'PCLZIP_OPT_REMOVE_PATH', 77003 );
131
+ define( 'PCLZIP_OPT_REMOVE_ALL_PATH', 77004 );
132
+ define( 'PCLZIP_OPT_SET_CHMOD', 77005 );
133
+ define( 'PCLZIP_OPT_EXTRACT_AS_STRING', 77006 );
134
+ define( 'PCLZIP_OPT_NO_COMPRESSION', 77007 );
135
+ define( 'PCLZIP_OPT_BY_NAME', 77008 );
136
+ define( 'PCLZIP_OPT_BY_INDEX', 77009 );
137
+ define( 'PCLZIP_OPT_BY_EREG', 77010 );
138
+ define( 'PCLZIP_OPT_BY_PREG', 77011 );
139
+ define( 'PCLZIP_OPT_COMMENT', 77012 );
140
+ define( 'PCLZIP_OPT_ADD_COMMENT', 77013 );
141
+ define( 'PCLZIP_OPT_PREPEND_COMMENT', 77014 );
142
+ define( 'PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015 );
143
+ define( 'PCLZIP_OPT_REPLACE_NEWER', 77016 );
144
+ define( 'PCLZIP_OPT_STOP_ON_ERROR', 77017 );
145
+ // Having big trouble with crypt. Need to multiply 2 long int
146
+ // which is not correctly supported by PHP ...
147
+ //define( 'PCLZIP_OPT_CRYPT', 77018 );
148
+ define( 'PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019 );
149
+ define( 'PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020 );
150
+ define( 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020 ); // alias
151
+ define( 'PCLZIP_OPT_TEMP_FILE_ON', 77021 );
152
+ define( 'PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021 ); // alias
153
+ define( 'PCLZIP_OPT_TEMP_FILE_OFF', 77022 );
154
+ define( 'PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022 ); // alias
155
+
156
+ // ----- File description attributes
157
+ define( 'PCLZIP_ATT_FILE_NAME', 79001 );
158
+ define( 'PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002 );
159
+ define( 'PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003 );
160
+ define( 'PCLZIP_ATT_FILE_MTIME', 79004 );
161
+ define( 'PCLZIP_ATT_FILE_CONTENT', 79005 );
162
+ define( 'PCLZIP_ATT_FILE_COMMENT', 79006 );
163
+
164
+ // ----- Call backs values
165
+ define( 'PCLZIP_CB_PRE_EXTRACT', 78001 );
166
+ define( 'PCLZIP_CB_POST_EXTRACT', 78002 );
167
+ define( 'PCLZIP_CB_PRE_ADD', 78003 );
168
+ define( 'PCLZIP_CB_POST_ADD', 78004 );
169
+ /* For futur use
170
+ define( 'PCLZIP_CB_PRE_LIST', 78005 );
171
+ define( 'PCLZIP_CB_POST_LIST', 78006 );
172
+ define( 'PCLZIP_CB_PRE_DELETE', 78007 );
173
+ define( 'PCLZIP_CB_POST_DELETE', 78008 );
174
+ */
175
+
176
+ // --------------------------------------------------------------------------------
177
+ // Class : PclZip
178
+ // Description :
179
+ // PclZip is the class that represent a Zip archive.
180
+ // The public methods allow the manipulation of the archive.
181
+ // Attributes :
182
+ // Attributes must not be accessed directly.
183
+ // Methods :
184
+ // PclZip() : Object creator
185
+ // create() : Creates the Zip archive
186
+ // listContent() : List the content of the Zip archive
187
+ // extract() : Extract the content of the archive
188
+ // properties() : List the properties of the archive
189
+ // --------------------------------------------------------------------------------
190
+ class PclZip
191
+ {
192
+ // ----- Filename of the zip file
193
+ var $zipname = '';
194
+
195
+ // ----- File descriptor of the zip file
196
+ var $zip_fd = 0;
197
+
198
+ // ----- Internal error handling
199
+ var $error_code = 1;
200
+ var $error_string = '';
201
+
202
+ // ----- Current status of the magic_quotes_runtime
203
+ // This value store the php configuration for magic_quotes
204
+ // The class can then disable the magic_quotes and reset it after
205
+ var $magic_quotes_status;
206
+
207
+ // --------------------------------------------------------------------------------
208
+ // Function : PclZip()
209
+ // Description :
210
+ // Creates a PclZip object and set the name of the associated Zip archive
211
+ // filename.
212
+ // Note that no real action is taken, if the archive does not exist it is not
213
+ // created. Use create() for that.
214
+ // --------------------------------------------------------------------------------
215
+ function PclZip($p_zipname)
216
+ {
217
+
218
+ // ----- Tests the zlib
219
+ if (!function_exists('gzopen'))
220
+ {
221
+ die('Abort '.basename(__FILE__).' : Missing zlib extensions');
222
+ }
223
+
224
+ // ----- Set the attributes
225
+ $this->zipname = $p_zipname;
226
+ $this->zip_fd = 0;
227
+ $this->magic_quotes_status = -1;
228
+
229
+ // ----- Return
230
+ return;
231
+ }
232
+ // --------------------------------------------------------------------------------
233
+
234
+ // --------------------------------------------------------------------------------
235
+ // Function :
236
+ // create($p_filelist, $p_add_dir="", $p_remove_dir="")
237
+ // create($p_filelist, $p_option, $p_option_value, ...)
238
+ // Description :
239
+ // This method supports two different synopsis. The first one is historical.
240
+ // This method creates a Zip Archive. The Zip file is created in the
241
+ // filesystem. The files and directories indicated in $p_filelist
242
+ // are added in the archive. See the parameters description for the
243
+ // supported format of $p_filelist.
244
+ // When a directory is in the list, the directory and its content is added
245
+ // in the archive.
246
+ // In this synopsis, the function takes an optional variable list of
247
+ // options. See bellow the supported options.
248
+ // Parameters :
249
+ // $p_filelist : An array containing file or directory names, or
250
+ // a string containing one filename or one directory name, or
251
+ // a string containing a list of filenames and/or directory
252
+ // names separated by spaces.
253
+ // $p_add_dir : A path to add before the real path of the archived file,
254
+ // in order to have it memorized in the archive.
255
+ // $p_remove_dir : A path to remove from the real path of the file to archive,
256
+ // in order to have a shorter path memorized in the archive.
257
+ // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
258
+ // is removed first, before $p_add_dir is added.
259
+ // Options :
260
+ // PCLZIP_OPT_ADD_PATH :
261
+ // PCLZIP_OPT_REMOVE_PATH :
262
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
263
+ // PCLZIP_OPT_COMMENT :
264
+ // PCLZIP_CB_PRE_ADD :
265
+ // PCLZIP_CB_POST_ADD :
266
+ // Return Values :
267
+ // 0 on failure,
268
+ // The list of the added files, with a status of the add action.
269
+ // (see PclZip::listContent() for list entry format)
270
+ // --------------------------------------------------------------------------------
271
+ function create($p_filelist)
272
+ {
273
+ $v_result=1;
274
+
275
+ // ----- Reset the error handler
276
+ $this->privErrorReset();
277
+
278
+ // ----- Set default values
279
+ $v_options = array();
280
+ $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
281
+
282
+ // ----- Look for variable options arguments
283
+ $v_size = func_num_args();
284
+
285
+ // ----- Look for arguments
286
+ if ($v_size > 1) {
287
+ // ----- Get the arguments
288
+ $v_arg_list = func_get_args();
289
+
290
+ // ----- Remove from the options list the first argument
291
+ array_shift($v_arg_list);
292
+ $v_size--;
293
+
294
+ // ----- Look for first arg
295
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
296
+
297
+ // ----- Parse the options
298
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
299
+ array (PCLZIP_OPT_REMOVE_PATH => 'optional',
300
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
301
+ PCLZIP_OPT_ADD_PATH => 'optional',
302
+ PCLZIP_CB_PRE_ADD => 'optional',
303
+ PCLZIP_CB_POST_ADD => 'optional',
304
+ PCLZIP_OPT_NO_COMPRESSION => 'optional',
305
+ PCLZIP_OPT_COMMENT => 'optional',
306
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
307
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
308
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
309
+ //, PCLZIP_OPT_CRYPT => 'optional'
310
+ ));
311
+ if ($v_result != 1) {
312
+ return 0;
313
+ }
314
+ }
315
+
316
+ // ----- Look for 2 args
317
+ // Here we need to support the first historic synopsis of the
318
+ // method.
319
+ else {
320
+
321
+ // ----- Get the first argument
322
+ $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
323
+
324
+ // ----- Look for the optional second argument
325
+ if ($v_size == 2) {
326
+ $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
327
+ }
328
+ else if ($v_size > 2) {
329
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
330
+ "Invalid number / type of arguments");
331
+ return 0;
332
+ }
333
+ }
334
+ }
335
+
336
+ // ----- Look for default option values
337
+ $this->privOptionDefaultThreshold($v_options);
338
+
339
+ // ----- Init
340
+ $v_string_list = array();
341
+ $v_att_list = array();
342
+ $v_filedescr_list = array();
343
+ $p_result_list = array();
344
+
345
+ // ----- Look if the $p_filelist is really an array
346
+ if (is_array($p_filelist)) {
347
+
348
+ // ----- Look if the first element is also an array
349
+ // This will mean that this is a file description entry
350
+ if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
351
+ $v_att_list = $p_filelist;
352
+ }
353
+
354
+ // ----- The list is a list of string names
355
+ else {
356
+ $v_string_list = $p_filelist;
357
+ }
358
+ }
359
+
360
+ // ----- Look if the $p_filelist is a string
361
+ else if (is_string($p_filelist)) {
362
+ // ----- Create a list from the string
363
+ $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
364
+ }
365
+
366
+ // ----- Invalid variable type for $p_filelist
367
+ else {
368
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
369
+ return 0;
370
+ }
371
+
372
+ // ----- Reformat the string list
373
+ if (sizeof($v_string_list) != 0) {
374
+ foreach ($v_string_list as $v_string) {
375
+ if ($v_string != '') {
376
+ $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
377
+ }
378
+ else {
379
+ }
380
+ }
381
+ }
382
+
383
+ // ----- For each file in the list check the attributes
384
+ $v_supported_attributes
385
+ = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
386
+ ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
387
+ ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
388
+ ,PCLZIP_ATT_FILE_MTIME => 'optional'
389
+ ,PCLZIP_ATT_FILE_CONTENT => 'optional'
390
+ ,PCLZIP_ATT_FILE_COMMENT => 'optional'
391
+ );
392
+ foreach ($v_att_list as $v_entry) {
393
+ $v_result = $this->privFileDescrParseAtt($v_entry,
394
+ $v_filedescr_list[],
395
+ $v_options,
396
+ $v_supported_attributes);
397
+ if ($v_result != 1) {
398
+ return 0;
399
+ }
400
+ }
401
+
402
+ // ----- Expand the filelist (expand directories)
403
+ $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
404
+ if ($v_result != 1) {
405
+ return 0;
406
+ }
407
+
408
+ // ----- Call the create fct
409
+ $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
410
+ if ($v_result != 1) {
411
+ return 0;
412
+ }
413
+
414
+ // ----- Return
415
+ return $p_result_list;
416
+ }
417
+ // --------------------------------------------------------------------------------
418
+
419
+ // --------------------------------------------------------------------------------
420
+ // Function :
421
+ // add($p_filelist, $p_add_dir="", $p_remove_dir="")
422
+ // add($p_filelist, $p_option, $p_option_value, ...)
423
+ // Description :
424
+ // This method supports two synopsis. The first one is historical.
425
+ // This methods add the list of files in an existing archive.
426
+ // If a file with the same name already exists, it is added at the end of the
427
+ // archive, the first one is still present.
428
+ // If the archive does not exist, it is created.
429
+ // Parameters :
430
+ // $p_filelist : An array containing file or directory names, or
431
+ // a string containing one filename or one directory name, or
432
+ // a string containing a list of filenames and/or directory
433
+ // names separated by spaces.
434
+ // $p_add_dir : A path to add before the real path of the archived file,
435
+ // in order to have it memorized in the archive.
436
+ // $p_remove_dir : A path to remove from the real path of the file to archive,
437
+ // in order to have a shorter path memorized in the archive.
438
+ // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
439
+ // is removed first, before $p_add_dir is added.
440
+ // Options :
441
+ // PCLZIP_OPT_ADD_PATH :
442
+ // PCLZIP_OPT_REMOVE_PATH :
443
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
444
+ // PCLZIP_OPT_COMMENT :
445
+ // PCLZIP_OPT_ADD_COMMENT :
446
+ // PCLZIP_OPT_PREPEND_COMMENT :
447
+ // PCLZIP_CB_PRE_ADD :
448
+ // PCLZIP_CB_POST_ADD :
449
+ // Return Values :
450
+ // 0 on failure,
451
+ // The list of the added files, with a status of the add action.
452
+ // (see PclZip::listContent() for list entry format)
453
+ // --------------------------------------------------------------------------------
454
+ function add($p_filelist)
455
+ {
456
+ $v_result=1;
457
+
458
+ // ----- Reset the error handler
459
+ $this->privErrorReset();
460
+
461
+ // ----- Set default values
462
+ $v_options = array();
463
+ $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
464
+
465
+ // ----- Look for variable options arguments
466
+ $v_size = func_num_args();
467
+
468
+ // ----- Look for arguments
469
+ if ($v_size > 1) {
470
+ // ----- Get the arguments
471
+ $v_arg_list = func_get_args();
472
+
473
+ // ----- Remove form the options list the first argument
474
+ array_shift($v_arg_list);
475
+ $v_size--;
476
+
477
+ // ----- Look for first arg
478
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
479
+
480
+ // ----- Parse the options
481
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
482
+ array (PCLZIP_OPT_REMOVE_PATH => 'optional',
483
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
484
+ PCLZIP_OPT_ADD_PATH => 'optional',
485
+ PCLZIP_CB_PRE_ADD => 'optional',
486
+ PCLZIP_CB_POST_ADD => 'optional',
487
+ PCLZIP_OPT_NO_COMPRESSION => 'optional',
488
+ PCLZIP_OPT_COMMENT => 'optional',
489
+ PCLZIP_OPT_ADD_COMMENT => 'optional',
490
+ PCLZIP_OPT_PREPEND_COMMENT => 'optional',
491
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
492
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
493
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
494
+ //, PCLZIP_OPT_CRYPT => 'optional'
495
+ ));
496
+ if ($v_result != 1) {
497
+ return 0;
498
+ }
499
+ }
500
+
501
+ // ----- Look for 2 args
502
+ // Here we need to support the first historic synopsis of the
503
+ // method.
504
+ else {
505
+
506
+ // ----- Get the first argument
507
+ $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
508
+
509
+ // ----- Look for the optional second argument
510
+ if ($v_size == 2) {
511
+ $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
512
+ }
513
+ else if ($v_size > 2) {
514
+ // ----- Error log
515
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
516
+
517
+ // ----- Return
518
+ return 0;
519
+ }
520
+ }
521
+ }
522
+
523
+ // ----- Look for default option values
524
+ $this->privOptionDefaultThreshold($v_options);
525
+
526
+ // ----- Init
527
+ $v_string_list = array();
528
+ $v_att_list = array();
529
+ $v_filedescr_list = array();
530
+ $p_result_list = array();
531
+
532
+ // ----- Look if the $p_filelist is really an array
533
+ if (is_array($p_filelist)) {
534
+
535
+ // ----- Look if the first element is also an array
536
+ // This will mean that this is a file description entry
537
+ if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
538
+ $v_att_list = $p_filelist;
539
+ }
540
+
541
+ // ----- The list is a list of string names
542
+ else {
543
+ $v_string_list = $p_filelist;
544
+ }
545
+ }
546
+
547
+ // ----- Look if the $p_filelist is a string
548
+ else if (is_string($p_filelist)) {
549
+ // ----- Create a list from the string
550
+ $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
551
+ }
552
+
553
+ // ----- Invalid variable type for $p_filelist
554
+ else {
555
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");
556
+ return 0;
557
+ }
558
+
559
+ // ----- Reformat the string list
560
+ if (sizeof($v_string_list) != 0) {
561
+ foreach ($v_string_list as $v_string) {
562
+ $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
563
+ }
564
+ }
565
+
566
+ // ----- For each file in the list check the attributes
567
+ $v_supported_attributes
568
+ = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
569
+ ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
570
+ ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
571
+ ,PCLZIP_ATT_FILE_MTIME => 'optional'
572
+ ,PCLZIP_ATT_FILE_CONTENT => 'optional'
573
+ ,PCLZIP_ATT_FILE_COMMENT => 'optional'
574
+ );
575
+ foreach ($v_att_list as $v_entry) {
576
+ $v_result = $this->privFileDescrParseAtt($v_entry,
577
+ $v_filedescr_list[],
578
+ $v_options,
579
+ $v_supported_attributes);
580
+ if ($v_result != 1) {
581
+ return 0;
582
+ }
583
+ }
584
+
585
+ // ----- Expand the filelist (expand directories)
586
+ $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
587
+ if ($v_result != 1) {
588
+ return 0;
589
+ }
590
+
591
+ // ----- Call the create fct
592
+ $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
593
+ if ($v_result != 1) {
594
+ return 0;
595
+ }
596
+
597
+ // ----- Return
598
+ return $p_result_list;
599
+ }
600
+ // --------------------------------------------------------------------------------
601
+
602
+ // --------------------------------------------------------------------------------
603
+ // Function : listContent()
604
+ // Description :
605
+ // This public method, gives the list of the files and directories, with their
606
+ // properties.
607
+ // The properties of each entries in the list are (used also in other functions) :
608
+ // filename : Name of the file. For a create or add action it is the filename
609
+ // given by the user. For an extract function it is the filename
610
+ // of the extracted file.
611
+ // stored_filename : Name of the file / directory stored in the archive.
612
+ // size : Size of the stored file.
613
+ // compressed_size : Size of the file's data compressed in the archive
614
+ // (without the headers overhead)
615
+ // mtime : Last known modification date of the file (UNIX timestamp)
616
+ // comment : Comment associated with the file
617
+ // folder : true | false
618
+ // index : index of the file in the archive
619
+ // status : status of the action (depending of the action) :
620
+ // Values are :
621
+ // ok : OK !
622
+ // filtered : the file / dir is not extracted (filtered by user)
623
+ // already_a_directory : the file can not be extracted because a
624
+ // directory with the same name already exists
625
+ // write_protected : the file can not be extracted because a file
626
+ // with the same name already exists and is
627
+ // write protected
628
+ // newer_exist : the file was not extracted because a newer file exists
629
+ // path_creation_fail : the file is not extracted because the folder
630
+ // does not exist and can not be created
631
+ // write_error : the file was not extracted because there was a
632
+ // error while writing the file
633
+ // read_error : the file was not extracted because there was a error
634
+ // while reading the file
635
+ // invalid_header : the file was not extracted because of an archive
636
+ // format error (bad file header)
637
+ // Note that each time a method can continue operating when there
638
+ // is an action error on a file, the error is only logged in the file status.
639
+ // Return Values :
640
+ // 0 on an unrecoverable failure,
641
+ // The list of the files in the archive.
642
+ // --------------------------------------------------------------------------------
643
+ function listContent()
644
+ {
645
+ $v_result=1;
646
+
647
+ // ----- Reset the error handler
648
+ $this->privErrorReset();
649
+
650
+ // ----- Check archive
651
+ if (!$this->privCheckFormat()) {
652
+ return(0);
653
+ }
654
+
655
+ // ----- Call the extracting fct
656
+ $p_list = array();
657
+ if (($v_result = $this->privList($p_list)) != 1)
658
+ {
659
+ unset($p_list);
660
+ return(0);
661
+ }
662
+
663
+ // ----- Return
664
+ return $p_list;
665
+ }
666
+ // --------------------------------------------------------------------------------
667
+
668
+ // --------------------------------------------------------------------------------
669
+ // Function :
670
+ // extract($p_path="./", $p_remove_path="")
671
+ // extract([$p_option, $p_option_value, ...])
672
+ // Description :
673
+ // This method supports two synopsis. The first one is historical.
674
+ // This method extract all the files / directories from the archive to the
675
+ // folder indicated in $p_path.
676
+ // If you want to ignore the 'root' part of path of the memorized files
677
+ // you can indicate this in the optional $p_remove_path parameter.
678
+ // By default, if a newer file with the same name already exists, the
679
+ // file is not extracted.
680
+ //
681
+ // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
682
+ // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
683
+ // at the end of the path value of PCLZIP_OPT_PATH.
684
+ // Parameters :
685
+ // $p_path : Path where the files and directories are to be extracted
686
+ // $p_remove_path : First part ('root' part) of the memorized path
687
+ // (if any similar) to remove while extracting.
688
+ // Options :
689
+ // PCLZIP_OPT_PATH :
690
+ // PCLZIP_OPT_ADD_PATH :
691
+ // PCLZIP_OPT_REMOVE_PATH :
692
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
693
+ // PCLZIP_CB_PRE_EXTRACT :
694
+ // PCLZIP_CB_POST_EXTRACT :
695
+ // Return Values :
696
+ // 0 or a negative value on failure,
697
+ // The list of the extracted files, with a status of the action.
698
+ // (see PclZip::listContent() for list entry format)
699
+ // --------------------------------------------------------------------------------
700
+ function extract()
701
+ {
702
+ $v_result=1;
703
+
704
+ // ----- Reset the error handler
705
+ $this->privErrorReset();
706
+
707
+ // ----- Check archive
708
+ if (!$this->privCheckFormat()) {
709
+ return(0);
710
+ }
711
+
712
+ // ----- Set default values
713
+ $v_options = array();
714
+ // $v_path = "./";
715
+ $v_path = '';
716
+ $v_remove_path = "";
717
+ $v_remove_all_path = false;
718
+
719
+ // ----- Look for variable options arguments
720
+ $v_size = func_num_args();
721
+
722
+ // ----- Default values for option
723
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
724
+
725
+ // ----- Look for arguments
726
+ if ($v_size > 0) {
727
+ // ----- Get the arguments
728
+ $v_arg_list = func_get_args();
729
+
730
+ // ----- Look for first arg
731
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
732
+
733
+ // ----- Parse the options
734
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
735
+ array (PCLZIP_OPT_PATH => 'optional',
736
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
737
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
738
+ PCLZIP_OPT_ADD_PATH => 'optional',
739
+ PCLZIP_CB_PRE_EXTRACT => 'optional',
740
+ PCLZIP_CB_POST_EXTRACT => 'optional',
741
+ PCLZIP_OPT_SET_CHMOD => 'optional',
742
+ PCLZIP_OPT_BY_NAME => 'optional',
743
+ PCLZIP_OPT_BY_EREG => 'optional',
744
+ PCLZIP_OPT_BY_PREG => 'optional',
745
+ PCLZIP_OPT_BY_INDEX => 'optional',
746
+ PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
747
+ PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
748
+ PCLZIP_OPT_REPLACE_NEWER => 'optional'
749
+ ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
750
+ ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
751
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
752
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
753
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
754
+ ));
755
+ if ($v_result != 1) {
756
+ return 0;
757
+ }
758
+
759
+ // ----- Set the arguments
760
+ if (isset($v_options[PCLZIP_OPT_PATH])) {
761
+ $v_path = $v_options[PCLZIP_OPT_PATH];
762
+ }
763
+ if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
764
+ $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
765
+ }
766
+ if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
767
+ $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
768
+ }
769
+ if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
770
+ // ----- Check for '/' in last path char
771
+ if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
772
+ $v_path .= '/';
773
+ }
774
+ $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
775
+ }
776
+ }
777
+
778
+ // ----- Look for 2 args
779
+ // Here we need to support the first historic synopsis of the
780
+ // method.
781
+ else {
782
+
783
+ // ----- Get the first argument
784
+ $v_path = $v_arg_list[0];
785
+
786
+ // ----- Look for the optional second argument
787
+ if ($v_size == 2) {
788
+ $v_remove_path = $v_arg_list[1];
789
+ }
790
+ else if ($v_size > 2) {
791
+ // ----- Error log
792
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
793
+
794
+ // ----- Return
795
+ return 0;
796
+ }
797
+ }
798
+ }
799
+
800
+ // ----- Look for default option values
801
+ $this->privOptionDefaultThreshold($v_options);
802
+
803
+ // ----- Trace
804
+
805
+ // ----- Call the extracting fct
806
+ $p_list = array();
807
+ $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path,
808
+ $v_remove_all_path, $v_options);
809
+ if ($v_result < 1) {
810
+ unset($p_list);
811
+ return(0);
812
+ }
813
+
814
+ // ----- Return
815
+ return $p_list;
816
+ }
817
+ // --------------------------------------------------------------------------------
818
+
819
+
820
+ // --------------------------------------------------------------------------------
821
+ // Function :
822
+ // extractByIndex($p_index, $p_path="./", $p_remove_path="")
823
+ // extractByIndex($p_index, [$p_option, $p_option_value, ...])
824
+ // Description :
825
+ // This method supports two synopsis. The first one is historical.
826
+ // This method is doing a partial extract of the archive.
827
+ // The extracted files or folders are identified by their index in the
828
+ // archive (from 0 to n).
829
+ // Note that if the index identify a folder, only the folder entry is
830
+ // extracted, not all the files included in the archive.
831
+ // Parameters :
832
+ // $p_index : A single index (integer) or a string of indexes of files to
833
+ // extract. The form of the string is "0,4-6,8-12" with only numbers
834
+ // and '-' for range or ',' to separate ranges. No spaces or ';'
835
+ // are allowed.
836
+ // $p_path : Path where the files and directories are to be extracted
837
+ // $p_remove_path : First part ('root' part) of the memorized path
838
+ // (if any similar) to remove while extracting.
839
+ // Options :
840
+ // PCLZIP_OPT_PATH :
841
+ // PCLZIP_OPT_ADD_PATH :
842
+ // PCLZIP_OPT_REMOVE_PATH :
843
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
844
+ // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
845
+ // not as files.
846
+ // The resulting content is in a new field 'content' in the file
847
+ // structure.
848
+ // This option must be used alone (any other options are ignored).
849
+ // PCLZIP_CB_PRE_EXTRACT :
850
+ // PCLZIP_CB_POST_EXTRACT :
851
+ // Return Values :
852
+ // 0 on failure,
853
+ // The list of the extracted files, with a status of the action.
854
+ // (see PclZip::listContent() for list entry format)
855
+ // --------------------------------------------------------------------------------
856
+ //function extractByIndex($p_index, options...)
857
+ function extractByIndex($p_index)
858
+ {
859
+ $v_result=1;
860
+
861
+ // ----- Reset the error handler
862
+ $this->privErrorReset();
863
+
864
+ // ----- Check archive
865
+ if (!$this->privCheckFormat()) {
866
+ return(0);
867
+ }
868
+
869
+ // ----- Set default values
870
+ $v_options = array();
871
+ // $v_path = "./";
872
+ $v_path = '';
873
+ $v_remove_path = "";
874
+ $v_remove_all_path = false;
875
+
876
+ // ----- Look for variable options arguments
877
+ $v_size = func_num_args();
878
+
879
+ // ----- Default values for option
880
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
881
+
882
+ // ----- Look for arguments
883
+ if ($v_size > 1) {
884
+ // ----- Get the arguments
885
+ $v_arg_list = func_get_args();
886
+
887
+ // ----- Remove form the options list the first argument
888
+ array_shift($v_arg_list);
889
+ $v_size--;
890
+
891
+ // ----- Look for first arg
892
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
893
+
894
+ // ----- Parse the options
895
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
896
+ array (PCLZIP_OPT_PATH => 'optional',
897
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
898
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
899
+ PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
900
+ PCLZIP_OPT_ADD_PATH => 'optional',
901
+ PCLZIP_CB_PRE_EXTRACT => 'optional',
902
+ PCLZIP_CB_POST_EXTRACT => 'optional',
903
+ PCLZIP_OPT_SET_CHMOD => 'optional',
904
+ PCLZIP_OPT_REPLACE_NEWER => 'optional'
905
+ ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
906
+ ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
907
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
908
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
909
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
910
+ ));
911
+ if ($v_result != 1) {
912
+ return 0;
913
+ }
914
+
915
+ // ----- Set the arguments
916
+ if (isset($v_options[PCLZIP_OPT_PATH])) {
917
+ $v_path = $v_options[PCLZIP_OPT_PATH];
918
+ }
919
+ if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
920
+ $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
921
+ }
922
+ if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
923
+ $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
924
+ }
925
+ if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
926
+ // ----- Check for '/' in last path char
927
+ if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
928
+ $v_path .= '/';
929
+ }
930
+ $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
931
+ }
932
+ if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
933
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
934
+ }
935
+ else {
936
+ }
937
+ }
938
+
939
+ // ----- Look for 2 args
940
+ // Here we need to support the first historic synopsis of the
941
+ // method.
942
+ else {
943
+
944
+ // ----- Get the first argument
945
+ $v_path = $v_arg_list[0];
946
+
947
+ // ----- Look for the optional second argument
948
+ if ($v_size == 2) {
949
+ $v_remove_path = $v_arg_list[1];
950
+ }
951
+ else if ($v_size > 2) {
952
+ // ----- Error log
953
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
954
+
955
+ // ----- Return
956
+ return 0;
957
+ }
958
+ }
959
+ }
960
+
961
+ // ----- Trace
962
+
963
+ // ----- Trick
964
+ // Here I want to reuse extractByRule(), so I need to parse the $p_index
965
+ // with privParseOptions()
966
+ $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index);
967
+ $v_options_trick = array();
968
+ $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick,
969
+ array (PCLZIP_OPT_BY_INDEX => 'optional' ));
970
+ if ($v_result != 1) {
971
+ return 0;
972
+ }
973
+ $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
974
+
975
+ // ----- Look for default option values
976
+ $this->privOptionDefaultThreshold($v_options);
977
+
978
+ // ----- Call the extracting fct
979
+ if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
980
+ return(0);
981
+ }
982
+
983
+ // ----- Return
984
+ return $p_list;
985
+ }
986
+ // --------------------------------------------------------------------------------
987
+
988
+ // --------------------------------------------------------------------------------
989
+ // Function :
990
+ // delete([$p_option, $p_option_value, ...])
991
+ // Description :
992
+ // This method removes files from the archive.
993
+ // If no parameters are given, then all the archive is emptied.
994
+ // Parameters :
995
+ // None or optional arguments.
996
+ // Options :
997
+ // PCLZIP_OPT_BY_INDEX :
998
+ // PCLZIP_OPT_BY_NAME :
999
+ // PCLZIP_OPT_BY_EREG :
1000
+ // PCLZIP_OPT_BY_PREG :
1001
+ // Return Values :
1002
+ // 0 on failure,
1003
+ // The list of the files which are still present in the archive.
1004
+ // (see PclZip::listContent() for list entry format)
1005
+ // --------------------------------------------------------------------------------
1006
+ function delete()
1007
+ {
1008
+ $v_result=1;
1009
+
1010
+ // ----- Reset the error handler
1011
+ $this->privErrorReset();
1012
+
1013
+ // ----- Check archive
1014
+ if (!$this->privCheckFormat()) {
1015
+ return(0);
1016
+ }
1017
+
1018
+ // ----- Set default values
1019
+ $v_options = array();
1020
+
1021
+ // ----- Look for variable options arguments
1022
+ $v_size = func_num_args();
1023
+
1024
+ // ----- Look for arguments
1025
+ if ($v_size > 0) {
1026
+ // ----- Get the arguments
1027
+ $v_arg_list = func_get_args();
1028
+
1029
+ // ----- Parse the options
1030
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
1031
+ array (PCLZIP_OPT_BY_NAME => 'optional',
1032
+ PCLZIP_OPT_BY_EREG => 'optional',
1033
+ PCLZIP_OPT_BY_PREG => 'optional',
1034
+ PCLZIP_OPT_BY_INDEX => 'optional' ));
1035
+ if ($v_result != 1) {
1036
+ return 0;
1037
+ }
1038
+ }
1039
+
1040
+ // ----- Magic quotes trick
1041
+ $this->privDisableMagicQuotes();
1042
+
1043
+ // ----- Call the delete fct
1044
+ $v_list = array();
1045
+ if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
1046
+ $this->privSwapBackMagicQuotes();
1047
+ unset($v_list);
1048
+ return(0);
1049
+ }
1050
+
1051
+ // ----- Magic quotes trick
1052
+ $this->privSwapBackMagicQuotes();
1053
+
1054
+ // ----- Return
1055
+ return $v_list;
1056
+ }
1057
+ // --------------------------------------------------------------------------------
1058
+
1059
+ // --------------------------------------------------------------------------------
1060
+ // Function : deleteByIndex()
1061
+ // Description :
1062
+ // ***** Deprecated *****
1063
+ // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
1064
+ // --------------------------------------------------------------------------------
1065
+ function deleteByIndex($p_index)
1066
+ {
1067
+
1068
+ $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
1069
+
1070
+ // ----- Return
1071
+ return $p_list;
1072
+ }
1073
+ // --------------------------------------------------------------------------------
1074
+
1075
+ // --------------------------------------------------------------------------------
1076
+ // Function : properties()
1077
+ // Description :
1078
+ // This method gives the properties of the archive.
1079
+ // The properties are :
1080
+ // nb : Number of files in the archive
1081
+ // comment : Comment associated with the archive file
1082
+ // status : not_exist, ok
1083
+ // Parameters :
1084
+ // None
1085
+ // Return Values :
1086
+ // 0 on failure,
1087
+ // An array with the archive properties.
1088
+ // --------------------------------------------------------------------------------
1089
+ function properties()
1090
+ {
1091
+
1092
+ // ----- Reset the error handler
1093
+ $this->privErrorReset();
1094
+
1095
+ // ----- Magic quotes trick
1096
+ $this->privDisableMagicQuotes();
1097
+
1098
+ // ----- Check archive
1099
+ if (!$this->privCheckFormat()) {
1100
+ $this->privSwapBackMagicQuotes();
1101
+ return(0);
1102
+ }
1103
+
1104
+ // ----- Default properties
1105
+ $v_prop = array();
1106
+ $v_prop['comment'] = '';
1107
+ $v_prop['nb'] = 0;
1108
+ $v_prop['status'] = 'not_exist';
1109
+
1110
+ // ----- Look if file exists
1111
+ if (@is_file($this->zipname))
1112
+ {
1113
+ // ----- Open the zip file
1114
+ if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
1115
+ {
1116
+ $this->privSwapBackMagicQuotes();
1117
+
1118
+ // ----- Error log
1119
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
1120
+
1121
+ // ----- Return
1122
+ return 0;
1123
+ }
1124
+
1125
+ // ----- Read the central directory informations
1126
+ $v_central_dir = array();
1127
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
1128
+ {
1129
+ $this->privSwapBackMagicQuotes();
1130
+ return 0;
1131
+ }
1132
+
1133
+ // ----- Close the zip file
1134
+ $this->privCloseFd();
1135
+
1136
+ // ----- Set the user attributes
1137
+ $v_prop['comment'] = $v_central_dir['comment'];
1138
+ $v_prop['nb'] = $v_central_dir['entries'];
1139
+ $v_prop['status'] = 'ok';
1140
+ }
1141
+
1142
+ // ----- Magic quotes trick
1143
+ $this->privSwapBackMagicQuotes();
1144
+
1145
+ // ----- Return
1146
+ return $v_prop;
1147
+ }
1148
+ // --------------------------------------------------------------------------------
1149
+
1150
+ // --------------------------------------------------------------------------------
1151
+ // Function : duplicate()
1152
+ // Description :
1153
+ // This method creates an archive by copying the content of an other one. If
1154
+ // the archive already exist, it is replaced by the new one without any warning.
1155
+ // Parameters :
1156
+ // $p_archive : The filename of a valid archive, or
1157
+ // a valid PclZip object.
1158
+ // Return Values :
1159
+ // 1 on success.
1160
+ // 0 or a negative value on error (error code).
1161
+ // --------------------------------------------------------------------------------
1162
+ function duplicate($p_archive)
1163
+ {
1164
+ $v_result = 1;
1165
+
1166
+ // ----- Reset the error handler
1167
+ $this->privErrorReset();
1168
+
1169
+ // ----- Look if the $p_archive is a PclZip object
1170
+ if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip'))
1171
+ {
1172
+
1173
+ // ----- Duplicate the archive
1174
+ $v_result = $this->privDuplicate($p_archive->zipname);
1175
+ }
1176
+
1177
+ // ----- Look if the $p_archive is a string (so a filename)
1178
+ else if (is_string($p_archive))
1179
+ {
1180
+
1181
+ // ----- Check that $p_archive is a valid zip file
1182
+ // TBC : Should also check the archive format
1183
+ if (!is_file($p_archive)) {
1184
+ // ----- Error log
1185
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
1186
+ $v_result = PCLZIP_ERR_MISSING_FILE;
1187
+ }
1188
+ else {
1189
+ // ----- Duplicate the archive
1190
+ $v_result = $this->privDuplicate($p_archive);
1191
+ }
1192
+ }
1193
+
1194
+ // ----- Invalid variable
1195
+ else
1196
+ {
1197
+ // ----- Error log
1198
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
1199
+ $v_result = PCLZIP_ERR_INVALID_PARAMETER;
1200
+ }
1201
+
1202
+ // ----- Return
1203
+ return $v_result;
1204
+ }
1205
+ // --------------------------------------------------------------------------------
1206
+
1207
+ // --------------------------------------------------------------------------------
1208
+ // Function : merge()
1209
+ // Description :
1210
+ // This method merge the $p_archive_to_add archive at the end of the current
1211
+ // one ($this).
1212
+ // If the archive ($this) does not exist, the merge becomes a duplicate.
1213
+ // If the $p_archive_to_add archive does not exist, the merge is a success.
1214
+ // Parameters :
1215
+ // $p_archive_to_add : It can be directly the filename of a valid zip archive,
1216
+ // or a PclZip object archive.
1217
+ // Return Values :
1218
+ // 1 on success,
1219
+ // 0 or negative values on error (see below).
1220
+ // --------------------------------------------------------------------------------
1221
+ function merge($p_archive_to_add)
1222
+ {
1223
+ $v_result = 1;
1224
+
1225
+ // ----- Reset the error handler
1226
+ $this->privErrorReset();
1227
+
1228
+ // ----- Check archive
1229
+ if (!$this->privCheckFormat()) {
1230
+ return(0);
1231
+ }
1232
+
1233
+ // ----- Look if the $p_archive_to_add is a PclZip object
1234
+ if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip'))
1235
+ {
1236
+
1237
+ // ----- Merge the archive
1238
+ $v_result = $this->privMerge($p_archive_to_add);
1239
+ }
1240
+
1241
+ // ----- Look if the $p_archive_to_add is a string (so a filename)
1242
+ else if (is_string($p_archive_to_add))
1243
+ {
1244
+
1245
+ // ----- Create a temporary archive
1246
+ $v_object_archive = new PclZip($p_archive_to_add);
1247
+
1248
+ // ----- Merge the archive
1249
+ $v_result = $this->privMerge($v_object_archive);
1250
+ }
1251
+
1252
+ // ----- Invalid variable
1253
+ else
1254
+ {
1255
+ // ----- Error log
1256
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
1257
+ $v_result = PCLZIP_ERR_INVALID_PARAMETER;
1258
+ }
1259
+
1260
+ // ----- Return
1261
+ return $v_result;
1262
+ }
1263
+ // --------------------------------------------------------------------------------
1264
+
1265
+
1266
+
1267
+ // --------------------------------------------------------------------------------
1268
+ // Function : errorCode()
1269
+ // Description :
1270
+ // Parameters :
1271
+ // --------------------------------------------------------------------------------
1272
+ function errorCode()
1273
+ {
1274
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
1275
+ return(PclErrorCode());
1276
+ }
1277
+ else {
1278
+ return($this->error_code);
1279
+ }
1280
+ }
1281
+ // --------------------------------------------------------------------------------
1282
+
1283
+ // --------------------------------------------------------------------------------
1284
+ // Function : errorName()
1285
+ // Description :
1286
+ // Parameters :
1287
+ // --------------------------------------------------------------------------------
1288
+ function errorName($p_with_code=false)
1289
+ {
1290
+ $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
1291
+ PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
1292
+ PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
1293
+ PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
1294
+ PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
1295
+ PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
1296
+ PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
1297
+ PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
1298
+ PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
1299
+ PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
1300
+ PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
1301
+ PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
1302
+ PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
1303
+ PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
1304
+ PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
1305
+ PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
1306
+ PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
1307
+ PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
1308
+ PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION'
1309
+ ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE'
1310
+ ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'
1311
+ );
1312
+
1313
+ if (isset($v_name[$this->error_code])) {
1314
+ $v_value = $v_name[$this->error_code];
1315
+ }
1316
+ else {
1317
+ $v_value = 'NoName';
1318
+ }
1319
+
1320
+ if ($p_with_code) {
1321
+ return($v_value.' ('.$this->error_code.')');
1322
+ }
1323
+ else {
1324
+ return($v_value);
1325
+ }
1326
+ }
1327
+ // --------------------------------------------------------------------------------
1328
+
1329
+ // --------------------------------------------------------------------------------
1330
+ // Function : errorInfo()
1331
+ // Description :
1332
+ // Parameters :
1333
+ // --------------------------------------------------------------------------------
1334
+ function errorInfo($p_full=false)
1335
+ {
1336
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
1337
+ return(PclErrorString());
1338
+ }
1339
+ else {
1340
+ if ($p_full) {
1341
+ return($this->errorName(true)." : ".$this->error_string);
1342
+ }
1343
+ else {
1344
+ return($this->error_string." [code ".$this->error_code."]");
1345
+ }
1346
+ }
1347
+ }
1348
+ // --------------------------------------------------------------------------------
1349
+
1350
+
1351
+ // --------------------------------------------------------------------------------
1352
+ // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
1353
+ // ***** *****
1354
+ // ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY *****
1355
+ // --------------------------------------------------------------------------------
1356
+
1357
+
1358
+
1359
+ // --------------------------------------------------------------------------------
1360
+ // Function : privCheckFormat()
1361
+ // Description :
1362
+ // This method check that the archive exists and is a valid zip archive.
1363
+ // Several level of check exists. (futur)
1364
+ // Parameters :
1365
+ // $p_level : Level of check. Default 0.
1366
+ // 0 : Check the first bytes (magic codes) (default value))
1367
+ // 1 : 0 + Check the central directory (futur)
1368
+ // 2 : 1 + Check each file header (futur)
1369
+ // Return Values :
1370
+ // true on success,
1371
+ // false on error, the error code is set.
1372
+ // --------------------------------------------------------------------------------
1373
+ function privCheckFormat($p_level=0)
1374
+ {
1375
+ $v_result = true;
1376
+
1377
+ // ----- Reset the file system cache
1378
+ clearstatcache();
1379
+
1380
+ // ----- Reset the error handler
1381
+ $this->privErrorReset();
1382
+
1383
+ // ----- Look if the file exits
1384
+ if (!is_file($this->zipname)) {
1385
+ // ----- Error log
1386
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");
1387
+ return(false);
1388
+ }
1389
+
1390
+ // ----- Check that the file is readeable
1391
+ if (!is_readable($this->zipname)) {
1392
+ // ----- Error log
1393
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");
1394
+ return(false);
1395
+ }
1396
+
1397
+ // ----- Check the magic code
1398
+ // TBC
1399
+
1400
+ // ----- Check the central header
1401
+ // TBC
1402
+
1403
+ // ----- Check each file header
1404
+ // TBC
1405
+
1406
+ // ----- Return
1407
+ return $v_result;
1408
+ }
1409
+ // --------------------------------------------------------------------------------
1410
+
1411
+ // --------------------------------------------------------------------------------
1412
+ // Function : privParseOptions()
1413
+ // Description :
1414
+ // This internal methods reads the variable list of arguments ($p_options_list,
1415
+ // $p_size) and generate an array with the options and values ($v_result_list).
1416
+ // $v_requested_options contains the options that can be present and those that
1417
+ // must be present.
1418
+ // $v_requested_options is an array, with the option value as key, and 'optional',
1419
+ // or 'mandatory' as value.
1420
+ // Parameters :
1421
+ // See above.
1422
+ // Return Values :
1423
+ // 1 on success.
1424
+ // 0 on failure.
1425
+ // --------------------------------------------------------------------------------
1426
+ function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false)
1427
+ {
1428
+ $v_result=1;
1429
+
1430
+ // ----- Read the options
1431
+ $i=0;
1432
+ while ($i<$p_size) {
1433
+
1434
+ // ----- Check if the option is supported
1435
+ if (!isset($v_requested_options[$p_options_list[$i]])) {
1436
+ // ----- Error log
1437
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");
1438
+
1439
+ // ----- Return
1440
+ return PclZip::errorCode();
1441
+ }
1442
+
1443
+ // ----- Look for next option
1444
+ switch ($p_options_list[$i]) {
1445
+ // ----- Look for options that request a path value
1446
+ case PCLZIP_OPT_PATH :
1447
+ case PCLZIP_OPT_REMOVE_PATH :
1448
+ case PCLZIP_OPT_ADD_PATH :
1449
+ // ----- Check the number of parameters
1450
+ if (($i+1) >= $p_size) {
1451
+ // ----- Error log
1452
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1453
+
1454
+ // ----- Return
1455
+ return PclZip::errorCode();
1456
+ }
1457
+
1458
+ // ----- Get the value
1459
+ $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
1460
+ $i++;
1461
+ break;
1462
+
1463
+ case PCLZIP_OPT_TEMP_FILE_THRESHOLD :
1464
+ // ----- Check the number of parameters
1465
+ if (($i+1) >= $p_size) {
1466
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1467
+ return PclZip::errorCode();
1468
+ }
1469
+
1470
+ // ----- Check for incompatible options
1471
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
1472
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
1473
+ return PclZip::errorCode();
1474
+ }
1475
+
1476
+ // ----- Check the value
1477
+ $v_value = $p_options_list[$i+1];
1478
+ if ((!is_integer($v_value)) || ($v_value<0)) {
1479
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1480
+ return PclZip::errorCode();
1481
+ }
1482
+
1483
+ // ----- Get the value (and convert it in bytes)
1484
+ $v_result_list[$p_options_list[$i]] = $v_value*1048576;
1485
+ $i++;
1486
+ break;
1487
+
1488
+ case PCLZIP_OPT_TEMP_FILE_ON :
1489
+ // ----- Check for incompatible options
1490
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
1491
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
1492
+ return PclZip::errorCode();
1493
+ }
1494
+
1495
+ $v_result_list[$p_options_list[$i]] = true;
1496
+ break;
1497
+
1498
+ case PCLZIP_OPT_TEMP_FILE_OFF :
1499
+ // ----- Check for incompatible options
1500
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
1501
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
1502
+ return PclZip::errorCode();
1503
+ }
1504
+ // ----- Check for incompatible options
1505
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
1506
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
1507
+ return PclZip::errorCode();
1508
+ }
1509
+
1510
+ $v_result_list[$p_options_list[$i]] = true;
1511
+ break;
1512
+
1513
+ case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION :
1514
+ // ----- Check the number of parameters
1515
+ if (($i+1) >= $p_size) {
1516
+ // ----- Error log
1517
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1518
+
1519
+ // ----- Return
1520
+ return PclZip::errorCode();
1521
+ }
1522
+
1523
+ // ----- Get the value
1524
+ if ( is_string($p_options_list[$i+1])
1525
+ && ($p_options_list[$i+1] != '')) {
1526
+ $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
1527
+ $i++;
1528
+ }
1529
+ else {
1530
+ }
1531
+ break;
1532
+
1533
+ // ----- Look for options that request an array of string for value
1534
+ case PCLZIP_OPT_BY_NAME :
1535
+ // ----- Check the number of parameters
1536
+ if (($i+1) >= $p_size) {
1537
+ // ----- Error log
1538
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1539
+
1540
+ // ----- Return
1541
+ return PclZip::errorCode();
1542
+ }
1543
+
1544
+ // ----- Get the value
1545
+ if (is_string($p_options_list[$i+1])) {
1546
+ $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1];
1547
+ }
1548
+ else if (is_array($p_options_list[$i+1])) {
1549
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1550
+ }
1551
+ else {
1552
+ // ----- Error log
1553
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1554
+
1555
+ // ----- Return
1556
+ return PclZip::errorCode();
1557
+ }
1558
+ $i++;
1559
+ break;
1560
+
1561
+ // ----- Look for options that request an EREG or PREG expression
1562
+ case PCLZIP_OPT_BY_EREG :
1563
+ // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
1564
+ // to PCLZIP_OPT_BY_PREG
1565
+ $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
1566
+ case PCLZIP_OPT_BY_PREG :
1567
+ //case PCLZIP_OPT_CRYPT :
1568
+ // ----- Check the number of parameters
1569
+ if (($i+1) >= $p_size) {
1570
+ // ----- Error log
1571
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1572
+
1573
+ // ----- Return
1574
+ return PclZip::errorCode();
1575
+ }
1576
+
1577
+ // ----- Get the value
1578
+ if (is_string($p_options_list[$i+1])) {
1579
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1580
+ }
1581
+ else {
1582
+ // ----- Error log
1583
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1584
+
1585
+ // ----- Return
1586
+ return PclZip::errorCode();
1587
+ }
1588
+ $i++;
1589
+ break;
1590
+
1591
+ // ----- Look for options that takes a string
1592
+ case PCLZIP_OPT_COMMENT :
1593
+ case PCLZIP_OPT_ADD_COMMENT :
1594
+ case PCLZIP_OPT_PREPEND_COMMENT :
1595
+ // ----- Check the number of parameters
1596
+ if (($i+1) >= $p_size) {
1597
+ // ----- Error log
1598
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1599
+ "Missing parameter value for option '"
1600
+ .PclZipUtilOptionText($p_options_list[$i])
1601
+ ."'");
1602
+
1603
+ // ----- Return
1604
+ return PclZip::errorCode();
1605
+ }
1606
+
1607
+ // ----- Get the value
1608
+ if (is_string($p_options_list[$i+1])) {
1609
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1610
+ }
1611
+ else {
1612
+ // ----- Error log
1613
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
1614
+ "Wrong parameter value for option '"
1615
+ .PclZipUtilOptionText($p_options_list[$i])
1616
+ ."'");
1617
+
1618
+ // ----- Return
1619
+ return PclZip::errorCode();
1620
+ }
1621
+ $i++;
1622
+ break;
1623
+
1624
+ // ----- Look for options that request an array of index
1625
+ case PCLZIP_OPT_BY_INDEX :
1626
+ // ----- Check the number of parameters
1627
+ if (($i+1) >= $p_size) {
1628
+ // ----- Error log
1629
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1630
+
1631
+ // ----- Return
1632
+ return PclZip::errorCode();
1633
+ }
1634
+
1635
+ // ----- Get the value
1636
+ $v_work_list = array();
1637
+ if (is_string($p_options_list[$i+1])) {
1638
+
1639
+ // ----- Remove spaces
1640
+ $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', '');
1641
+
1642
+ // ----- Parse items
1643
+ $v_work_list = explode(",", $p_options_list[$i+1]);
1644
+ }
1645
+ else if (is_integer($p_options_list[$i+1])) {
1646
+ $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1];
1647
+ }
1648
+ else if (is_array($p_options_list[$i+1])) {
1649
+ $v_work_list = $p_options_list[$i+1];
1650
+ }
1651
+ else {
1652
+ // ----- Error log
1653
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1654
+
1655
+ // ----- Return
1656
+ return PclZip::errorCode();
1657
+ }
1658
+
1659
+ // ----- Reduce the index list
1660
+ // each index item in the list must be a couple with a start and
1661
+ // an end value : [0,3], [5-5], [8-10], ...
1662
+ // ----- Check the format of each item
1663
+ $v_sort_flag=false;
1664
+ $v_sort_value=0;
1665
+ for ($j=0; $j<sizeof($v_work_list); $j++) {
1666
+ // ----- Explode the item
1667
+ $v_item_list = explode("-", $v_work_list[$j]);
1668
+ $v_size_item_list = sizeof($v_item_list);
1669
+
1670
+ // ----- TBC : Here we might check that each item is a
1671
+ // real integer ...
1672
+
1673
+ // ----- Look for single value
1674
+ if ($v_size_item_list == 1) {
1675
+ // ----- Set the option value
1676
+ $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
1677
+ $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0];
1678
+ }
1679
+ elseif ($v_size_item_list == 2) {
1680
+ // ----- Set the option value
1681
+ $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
1682
+ $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1];
1683
+ }
1684
+ else {
1685
+ // ----- Error log
1686
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1687
+
1688
+ // ----- Return
1689
+ return PclZip::errorCode();
1690
+ }
1691
+
1692
+
1693
+ // ----- Look for list sort
1694
+ if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {
1695
+ $v_sort_flag=true;
1696
+
1697
+ // ----- TBC : An automatic sort should be writen ...
1698
+ // ----- Error log
1699
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1700
+
1701
+ // ----- Return
1702
+ return PclZip::errorCode();
1703
+ }
1704
+ $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];
1705
+ }
1706
+
1707
+ // ----- Sort the items
1708
+ if ($v_sort_flag) {
1709
+ // TBC : To Be Completed
1710
+ }
1711
+
1712
+ // ----- Next option
1713
+ $i++;
1714
+ break;
1715
+
1716
+ // ----- Look for options that request no value
1717
+ case PCLZIP_OPT_REMOVE_ALL_PATH :
1718
+ case PCLZIP_OPT_EXTRACT_AS_STRING :
1719
+ case PCLZIP_OPT_NO_COMPRESSION :
1720
+ case PCLZIP_OPT_EXTRACT_IN_OUTPUT :
1721
+ case PCLZIP_OPT_REPLACE_NEWER :
1722
+ case PCLZIP_OPT_STOP_ON_ERROR :
1723
+ $v_result_list[$p_options_list[$i]] = true;
1724
+ break;
1725
+
1726
+ // ----- Look for options that request an octal value
1727
+ case PCLZIP_OPT_SET_CHMOD :
1728
+ // ----- Check the number of parameters
1729
+ if (($i+1) >= $p_size) {
1730
+ // ----- Error log
1731
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1732
+
1733
+ // ----- Return
1734
+ return PclZip::errorCode();
1735
+ }
1736
+
1737
+ // ----- Get the value
1738
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1739
+ $i++;
1740
+ break;
1741
+
1742
+ // ----- Look for options that request a call-back
1743
+ case PCLZIP_CB_PRE_EXTRACT :
1744
+ case PCLZIP_CB_POST_EXTRACT :
1745
+ case PCLZIP_CB_PRE_ADD :
1746
+ case PCLZIP_CB_POST_ADD :
1747
+ /* for futur use
1748
+ case PCLZIP_CB_PRE_DELETE :
1749
+ case PCLZIP_CB_POST_DELETE :
1750
+ case PCLZIP_CB_PRE_LIST :
1751
+ case PCLZIP_CB_POST_LIST :
1752
+ */
1753
+ // ----- Check the number of parameters
1754
+ if (($i+1) >= $p_size) {
1755
+ // ----- Error log
1756
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1757
+
1758
+ // ----- Return
1759
+ return PclZip::errorCode();
1760
+ }
1761
+
1762
+ // ----- Get the value
1763
+ $v_function_name = $p_options_list[$i+1];
1764
+
1765
+ // ----- Check that the value is a valid existing function
1766
+ if (!function_exists($v_function_name)) {
1767
+ // ----- Error log
1768
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1769
+
1770
+ // ----- Return
1771
+ return PclZip::errorCode();
1772
+ }
1773
+
1774
+ // ----- Set the attribute
1775
+ $v_result_list[$p_options_list[$i]] = $v_function_name;
1776
+ $i++;
1777
+ break;
1778
+
1779
+ default :
1780
+ // ----- Error log
1781
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1782
+ "Unknown parameter '"
1783
+ .$p_options_list[$i]."'");
1784
+
1785
+ // ----- Return
1786
+ return PclZip::errorCode();
1787
+ }
1788
+
1789
+ // ----- Next options
1790
+ $i++;
1791
+ }
1792
+
1793
+ // ----- Look for mandatory options
1794
+ if ($v_requested_options !== false) {
1795
+ for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
1796
+ // ----- Look for mandatory option
1797
+ if ($v_requested_options[$key] == 'mandatory') {
1798
+ // ----- Look if present
1799
+ if (!isset($v_result_list[$key])) {
1800
+ // ----- Error log
1801
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
1802
+
1803
+ // ----- Return
1804
+ return PclZip::errorCode();
1805
+ }
1806
+ }
1807
+ }
1808
+ }
1809
+
1810
+ // ----- Look for default values
1811
+ if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
1812
+
1813
+ }
1814
+
1815
+ // ----- Return
1816
+ return $v_result;
1817
+ }
1818
+ // --------------------------------------------------------------------------------
1819
+
1820
+ // --------------------------------------------------------------------------------
1821
+ // Function : privOptionDefaultThreshold()
1822
+ // Description :
1823
+ // Parameters :
1824
+ // Return Values :
1825
+ // --------------------------------------------------------------------------------
1826
+ function privOptionDefaultThreshold(&$p_options)
1827
+ {
1828
+ $v_result=1;
1829
+
1830
+ if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
1831
+ || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {
1832
+ return $v_result;
1833
+ }
1834
+
1835
+ // ----- Get 'memory_limit' configuration value
1836
+ $v_memory_limit = ini_get('memory_limit');
1837
+ $v_memory_limit = trim($v_memory_limit);
1838
+ $last = strtolower(substr($v_memory_limit, -1));
1839
+
1840
+ if($last == 'g')
1841
+ //$v_memory_limit = $v_memory_limit*1024*1024*1024;
1842
+ $v_memory_limit = $v_memory_limit*1073741824;
1843
+ if($last == 'm')
1844
+ //$v_memory_limit = $v_memory_limit*1024*1024;
1845
+ $v_memory_limit = $v_memory_limit*1048576;
1846
+ if($last == 'k')
1847
+ $v_memory_limit = $v_memory_limit*1024;
1848
+
1849
+ $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO);
1850
+
1851
+
1852
+ // ----- Sanity check : No threshold if value lower than 1M
1853
+ if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
1854
+ unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
1855
+ }
1856
+
1857
+ // ----- Return
1858
+ return $v_result;
1859
+ }
1860
+ // --------------------------------------------------------------------------------
1861
+
1862
+ // --------------------------------------------------------------------------------
1863
+ // Function : privFileDescrParseAtt()
1864
+ // Description :
1865
+ // Parameters :
1866
+ // Return Values :
1867
+ // 1 on success.
1868
+ // 0 on failure.
1869
+ // --------------------------------------------------------------------------------
1870
+ function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false)
1871
+ {
1872
+ $v_result=1;
1873
+
1874
+ // ----- For each file in the list check the attributes
1875
+ foreach ($p_file_list as $v_key => $v_value) {
1876
+
1877
+ // ----- Check if the option is supported
1878
+ if (!isset($v_requested_options[$v_key])) {
1879
+ // ----- Error log
1880
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file");
1881
+
1882
+ // ----- Return
1883
+ return PclZip::errorCode();
1884
+ }
1885
+
1886
+ // ----- Look for attribute
1887
+ switch ($v_key) {
1888
+ case PCLZIP_ATT_FILE_NAME :
1889
+ if (!is_string($v_value)) {
1890
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1891
+ return PclZip::errorCode();
1892
+ }
1893
+
1894
+ $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
1895
+
1896
+ if ($p_filedescr['filename'] == '') {
1897
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'");
1898
+ return PclZip::errorCode();
1899
+ }
1900
+
1901
+ break;
1902
+
1903
+ case PCLZIP_ATT_FILE_NEW_SHORT_NAME :
1904
+ if (!is_string($v_value)) {
1905
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1906
+ return PclZip::errorCode();
1907
+ }
1908
+
1909
+ $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
1910
+
1911
+ if ($p_filedescr['new_short_name'] == '') {
1912
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'");
1913
+ return PclZip::errorCode();
1914
+ }
1915
+ break;
1916
+
1917
+ case PCLZIP_ATT_FILE_NEW_FULL_NAME :
1918
+ if (!is_string($v_value)) {
1919
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1920
+ return PclZip::errorCode();
1921
+ }
1922
+
1923
+ $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
1924
+
1925
+ if ($p_filedescr['new_full_name'] == '') {
1926
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'");
1927
+ return PclZip::errorCode();
1928
+ }
1929
+ break;
1930
+
1931
+ // ----- Look for options that takes a string
1932
+ case PCLZIP_ATT_FILE_COMMENT :
1933
+ if (!is_string($v_value)) {
1934
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1935
+ return PclZip::errorCode();
1936
+ }
1937
+
1938
+ $p_filedescr['comment'] = $v_value;
1939
+ break;
1940
+
1941
+ case PCLZIP_ATT_FILE_MTIME :
1942
+ if (!is_integer($v_value)) {
1943
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'");
1944
+ return PclZip::errorCode();
1945
+ }
1946
+
1947
+ $p_filedescr['mtime'] = $v_value;
1948
+ break;
1949
+
1950
+ case PCLZIP_ATT_FILE_CONTENT :
1951
+ $p_filedescr['content'] = $v_value;
1952
+ break;
1953
+
1954
+ default :
1955
+ // ----- Error log
1956
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1957
+ "Unknown parameter '".$v_key."'");
1958
+
1959
+ // ----- Return
1960
+ return PclZip::errorCode();
1961
+ }
1962
+
1963
+ // ----- Look for mandatory options
1964
+ if ($v_requested_options !== false) {
1965
+ for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
1966
+ // ----- Look for mandatory option
1967
+ if ($v_requested_options[$key] == 'mandatory') {
1968
+ // ----- Look if present
1969
+ if (!isset($p_file_list[$key])) {
1970
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
1971
+ return PclZip::errorCode();
1972
+ }
1973
+ }
1974
+ }
1975
+ }
1976
+
1977
+ // end foreach
1978
+ }
1979
+
1980
+ // ----- Return
1981
+ return $v_result;
1982
+ }
1983
+ // --------------------------------------------------------------------------------
1984
+
1985
+ // --------------------------------------------------------------------------------
1986
+ // Function : privFileDescrExpand()
1987
+ // Description :
1988
+ // This method look for each item of the list to see if its a file, a folder
1989
+ // or a string to be added as file. For any other type of files (link, other)
1990
+ // just ignore the item.
1991
+ // Then prepare the information that will be stored for that file.
1992
+ // When its a folder, expand the folder with all the files that are in that
1993
+ // folder (recursively).
1994
+ // Parameters :
1995
+ // Return Values :
1996
+ // 1 on success.
1997
+ // 0 on failure.
1998
+ // --------------------------------------------------------------------------------
1999
+ function privFileDescrExpand(&$p_filedescr_list, &$p_options)
2000
+ {
2001
+ $v_result=1;
2002
+
2003
+ // ----- Create a result list
2004
+ $v_result_list = array();
2005
+
2006
+ // ----- Look each entry
2007
+ for ($i=0; $i<sizeof($p_filedescr_list); $i++) {
2008
+
2009
+ // ----- Get filedescr
2010
+ $v_descr = $p_filedescr_list[$i];
2011
+
2012
+ // ----- Reduce the filename
2013
+ $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);
2014
+ $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);
2015
+
2016
+ // ----- Look for real file or folder
2017
+ if (file_exists($v_descr['filename'])) {
2018
+ if (@is_file($v_descr['filename'])) {
2019
+ $v_descr['type'] = 'file';
2020
+ }
2021
+ else if (@is_dir($v_descr['filename'])) {
2022
+ $v_descr['type'] = 'folder';
2023
+ }
2024
+ else if (@is_link($v_descr['filename'])) {
2025
+ // skip
2026
+ continue;
2027
+ }
2028
+ else {
2029
+ // skip
2030
+ continue;
2031
+ }
2032
+ }
2033
+
2034
+ // ----- Look for string added as file
2035
+ else if (isset($v_descr['content'])) {
2036
+ $v_descr['type'] = 'virtual_file';
2037
+ }
2038
+
2039
+ // ----- Missing file
2040
+ else {
2041
+ // ----- Error log
2042
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$v_descr['filename']."' does not exist");
2043
+
2044
+ // ----- Return
2045
+ return PclZip::errorCode();
2046
+ }
2047
+
2048
+ // ----- Calculate the stored filename
2049
+ $this->privCalculateStoredFilename($v_descr, $p_options);
2050
+
2051
+ // ----- Add the descriptor in result list
2052
+ $v_result_list[sizeof($v_result_list)] = $v_descr;
2053
+
2054
+ // ----- Look for folder
2055
+ if ($v_descr['type'] == 'folder') {
2056
+ // ----- List of items in folder
2057
+ $v_dirlist_descr = array();
2058
+ $v_dirlist_nb = 0;
2059
+ if ($v_folder_handler = @opendir($v_descr['filename'])) {
2060
+ while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
2061
+
2062
+ // ----- Skip '.' and '..'
2063
+ if (($v_item_handler == '.') || ($v_item_handler == '..')) {
2064
+ continue;
2065
+ }
2066
+
2067
+ // ----- Compose the full filename
2068
+ $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler;
2069
+
2070
+ // ----- Look for different stored filename
2071
+ // Because the name of the folder was changed, the name of the
2072
+ // files/sub-folders also change
2073
+ if (($v_descr['stored_filename'] != $v_descr['filename'])
2074
+ && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
2075
+ if ($v_descr['stored_filename'] != '') {
2076
+ $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler;
2077
+ }
2078
+ else {
2079
+ $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
2080
+ }
2081
+ }
2082
+
2083
+ $v_dirlist_nb++;
2084
+ }
2085
+
2086
+ @closedir($v_folder_handler);
2087
+ }
2088
+ else {
2089
+ // TBC : unable to open folder in read mode
2090
+ }
2091
+
2092
+ // ----- Expand each element of the list
2093
+ if ($v_dirlist_nb != 0) {
2094
+ // ----- Expand
2095
+ if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
2096
+ return $v_result;
2097
+ }
2098
+
2099
+ // ----- Concat the resulting list
2100
+ $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
2101
+ }
2102
+ else {
2103
+ }
2104
+
2105
+ // ----- Free local array
2106
+ unset($v_dirlist_descr);
2107
+ }
2108
+ }
2109
+
2110
+ // ----- Get the result list
2111
+ $p_filedescr_list = $v_result_list;
2112
+
2113
+ // ----- Return
2114
+ return $v_result;
2115
+ }
2116
+ // --------------------------------------------------------------------------------
2117
+
2118
+ // --------------------------------------------------------------------------------
2119
+ // Function : privCreate()
2120
+ // Description :
2121
+ // Parameters :
2122
+ // Return Values :
2123
+ // --------------------------------------------------------------------------------
2124
+ function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
2125
+ {
2126
+ $v_result=1;
2127
+ $v_list_detail = array();
2128
+
2129
+ // ----- Magic quotes trick
2130
+ $this->privDisableMagicQuotes();
2131
+
2132
+ // ----- Open the file in write mode
2133
+ if (($v_result = $this->privOpenFd('wb')) != 1)
2134
+ {
2135
+ // ----- Return
2136
+ return $v_result;
2137
+ }
2138
+
2139
+ // ----- Add the list of files
2140
+ $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
2141
+
2142
+ // ----- Close
2143
+ $this->privCloseFd();
2144
+
2145
+ // ----- Magic quotes trick
2146
+ $this->privSwapBackMagicQuotes();
2147
+
2148
+ // ----- Return
2149
+ return $v_result;
2150
+ }
2151
+ // --------------------------------------------------------------------------------
2152
+
2153
+ // --------------------------------------------------------------------------------
2154
+ // Function : privAdd()
2155
+ // Description :
2156
+ // Parameters :
2157
+ // Return Values :
2158
+ // --------------------------------------------------------------------------------
2159
+ function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
2160
+ {
2161
+ $v_result=1;
2162
+ $v_list_detail = array();
2163
+
2164
+ // ----- Look if the archive exists or is empty
2165
+ if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0))
2166
+ {
2167
+
2168
+ // ----- Do a create
2169
+ $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
2170
+
2171
+ // ----- Return
2172
+ return $v_result;
2173
+ }
2174
+ // ----- Magic quotes trick
2175
+ $this->privDisableMagicQuotes();
2176
+
2177
+ // ----- Open the zip file
2178
+ if (($v_result=$this->privOpenFd('rb')) != 1)
2179
+ {
2180
+ // ----- Magic quotes trick
2181
+ $this->privSwapBackMagicQuotes();
2182
+
2183
+ // ----- Return
2184
+ return $v_result;
2185
+ }
2186
+
2187
+ // ----- Read the central directory informations
2188
+ $v_central_dir = array();
2189
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
2190
+ {
2191
+ $this->privCloseFd();
2192
+ $this->privSwapBackMagicQuotes();
2193
+ return $v_result;
2194
+ }
2195
+
2196
+ // ----- Go to beginning of File
2197
+ @rewind($this->zip_fd);
2198
+
2199
+ // ----- Creates a temporay file
2200
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
2201
+
2202
+ // ----- Open the temporary file in write mode
2203
+ if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
2204
+ {
2205
+ $this->privCloseFd();
2206
+ $this->privSwapBackMagicQuotes();
2207
+
2208
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
2209
+
2210
+ // ----- Return
2211
+ return PclZip::errorCode();
2212
+ }
2213
+
2214
+ // ----- Copy the files from the archive to the temporary file
2215
+ // TBC : Here I should better append the file and go back to erase the central dir
2216
+ $v_size = $v_central_dir['offset'];
2217
+ while ($v_size != 0)
2218
+ {
2219
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2220
+ $v_buffer = fread($this->zip_fd, $v_read_size);
2221
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
2222
+ $v_size -= $v_read_size;
2223
+ }
2224
+
2225
+ // ----- Swap the file descriptor
2226
+ // Here is a trick : I swap the temporary fd with the zip fd, in order to use
2227
+ // the following methods on the temporary fil and not the real archive
2228
+ $v_swap = $this->zip_fd;
2229
+ $this->zip_fd = $v_zip_temp_fd;
2230
+ $v_zip_temp_fd = $v_swap;
2231
+
2232
+ // ----- Add the files
2233
+ $v_header_list = array();
2234
+ if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
2235
+ {
2236
+ fclose($v_zip_temp_fd);
2237
+ $this->privCloseFd();
2238
+ @unlink($v_zip_temp_name);
2239
+ $this->privSwapBackMagicQuotes();
2240
+
2241
+ // ----- Return
2242
+ return $v_result;
2243
+ }
2244
+
2245
+ // ----- Store the offset of the central dir
2246
+ $v_offset = @ftell($this->zip_fd);
2247
+
2248
+ // ----- Copy the block of file headers from the old archive
2249
+ $v_size = $v_central_dir['size'];
2250
+ while ($v_size != 0)
2251
+ {
2252
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2253
+ $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
2254
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
2255
+ $v_size -= $v_read_size;
2256
+ }
2257
+
2258
+ // ----- Create the Central Dir files header
2259
+ for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++)
2260
+ {
2261
+ // ----- Create the file header
2262
+ if ($v_header_list[$i]['status'] == 'ok') {
2263
+ if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
2264
+ fclose($v_zip_temp_fd);
2265
+ $this->privCloseFd();
2266
+ @unlink($v_zip_temp_name);
2267
+ $this->privSwapBackMagicQuotes();
2268
+
2269
+ // ----- Return
2270
+ return $v_result;
2271
+ }
2272
+ $v_count++;
2273
+ }
2274
+
2275
+ // ----- Transform the header to a 'usable' info
2276
+ $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
2277
+ }
2278
+
2279
+ // ----- Zip file comment
2280
+ $v_comment = $v_central_dir['comment'];
2281
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
2282
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
2283
+ }
2284
+ if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
2285
+ $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT];
2286
+ }
2287
+ if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
2288
+ $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment;
2289
+ }
2290
+
2291
+ // ----- Calculate the size of the central header
2292
+ $v_size = @ftell($this->zip_fd)-$v_offset;
2293
+
2294
+ // ----- Create the central dir footer
2295
+ if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1)
2296
+ {
2297
+ // ----- Reset the file list
2298
+ unset($v_header_list);
2299
+ $this->privSwapBackMagicQuotes();
2300
+
2301
+ // ----- Return
2302
+ return $v_result;
2303
+ }
2304
+
2305
+ // ----- Swap back the file descriptor
2306
+ $v_swap = $this->zip_fd;
2307
+ $this->zip_fd = $v_zip_temp_fd;
2308
+ $v_zip_temp_fd = $v_swap;
2309
+
2310
+ // ----- Close
2311
+ $this->privCloseFd();
2312
+
2313
+ // ----- Close the temporary file
2314
+ @fclose($v_zip_temp_fd);
2315
+
2316
+ // ----- Magic quotes trick
2317
+ $this->privSwapBackMagicQuotes();
2318
+
2319
+ // ----- Delete the zip file
2320
+ // TBC : I should test the result ...
2321
+ @unlink($this->zipname);
2322
+
2323
+ // ----- Rename the temporary file
2324
+ // TBC : I should test the result ...
2325
+ //@rename($v_zip_temp_name, $this->zipname);
2326
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
2327
+
2328
+ // ----- Return
2329
+ return $v_result;
2330
+ }
2331
+ // --------------------------------------------------------------------------------
2332
+
2333
+ // --------------------------------------------------------------------------------
2334
+ // Function : privOpenFd()
2335
+ // Description :
2336
+ // Parameters :
2337
+ // --------------------------------------------------------------------------------
2338
+ function privOpenFd($p_mode)
2339
+ {
2340
+ $v_result=1;
2341
+
2342
+ // ----- Look if already open
2343
+ if ($this->zip_fd != 0)
2344
+ {
2345
+ // ----- Error log
2346
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open');
2347
+
2348
+ // ----- Return
2349
+ return PclZip::errorCode();
2350
+ }
2351
+
2352
+ // ----- Open the zip file
2353
+ if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0)
2354
+ {
2355
+ // ----- Error log
2356
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode');
2357
+
2358
+ // ----- Return
2359
+ return PclZip::errorCode();
2360
+ }
2361
+
2362
+ // ----- Return
2363
+ return $v_result;
2364
+ }
2365
+ // --------------------------------------------------------------------------------
2366
+
2367
+ // --------------------------------------------------------------------------------
2368
+ // Function : privCloseFd()
2369
+ // Description :
2370
+ // Parameters :
2371
+ // --------------------------------------------------------------------------------
2372
+ function privCloseFd()
2373
+ {
2374
+ $v_result=1;
2375
+
2376
+ if ($this->zip_fd != 0)
2377
+ @fclose($this->zip_fd);
2378
+ $this->zip_fd = 0;
2379
+
2380
+ // ----- Return
2381
+ return $v_result;
2382
+ }
2383
+ // --------------------------------------------------------------------------------
2384
+
2385
+ // --------------------------------------------------------------------------------
2386
+ // Function : privAddList()
2387
+ // Description :
2388
+ // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
2389
+ // different from the real path of the file. This is usefull if you want to have PclTar
2390
+ // running in any directory, and memorize relative path from an other directory.
2391
+ // Parameters :
2392
+ // $p_list : An array containing the file or directory names to add in the tar
2393
+ // $p_result_list : list of added files with their properties (specially the status field)
2394
+ // $p_add_dir : Path to add in the filename path archived
2395
+ // $p_remove_dir : Path to remove in the filename path archived
2396
+ // Return Values :
2397
+ // --------------------------------------------------------------------------------
2398
+ // function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
2399
+ function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
2400
+ {
2401
+ $v_result=1;
2402
+
2403
+ // ----- Add the files
2404
+ $v_header_list = array();
2405
+ if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
2406
+ {
2407
+ // ----- Return
2408
+ return $v_result;
2409
+ }
2410
+
2411
+ // ----- Store the offset of the central dir
2412
+ $v_offset = @ftell($this->zip_fd);
2413
+
2414
+ // ----- Create the Central Dir files header
2415
+ for ($i=0,$v_count=0; $i<sizeof($v_header_list); $i++)
2416
+ {
2417
+ // ----- Create the file header
2418
+ if ($v_header_list[$i]['status'] == 'ok') {
2419
+ if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
2420
+ // ----- Return
2421
+ return $v_result;
2422
+ }
2423
+ $v_count++;
2424
+ }
2425
+
2426
+ // ----- Transform the header to a 'usable' info
2427
+ $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
2428
+ }
2429
+
2430
+ // ----- Zip file comment
2431
+ $v_comment = '';
2432
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
2433
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
2434
+ }
2435
+
2436
+ // ----- Calculate the size of the central header
2437
+ $v_size = @ftell($this->zip_fd)-$v_offset;
2438
+
2439
+ // ----- Create the central dir footer
2440
+ if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1)
2441
+ {
2442
+ // ----- Reset the file list
2443
+ unset($v_header_list);
2444
+
2445
+ // ----- Return
2446
+ return $v_result;
2447
+ }
2448
+
2449
+ // ----- Return
2450
+ return $v_result;
2451
+ }
2452
+ // --------------------------------------------------------------------------------
2453
+
2454
+ // --------------------------------------------------------------------------------
2455
+ // Function : privAddFileList()
2456
+ // Description :
2457
+ // Parameters :
2458
+ // $p_filedescr_list : An array containing the file description
2459
+ // or directory names to add in the zip
2460
+ // $p_result_list : list of added files with their properties (specially the status field)
2461
+ // Return Values :
2462
+ // --------------------------------------------------------------------------------
2463
+ function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
2464
+ {
2465
+ $v_result=1;
2466
+ $v_header = array();
2467
+
2468
+ // ----- Recuperate the current number of elt in list
2469
+ $v_nb = sizeof($p_result_list);
2470
+
2471
+ // ----- Loop on the files
2472
+ for ($j=0; ($j<sizeof($p_filedescr_list)) && ($v_result==1); $j++) {
2473
+ // ----- Format the filename
2474
+ $p_filedescr_list[$j]['filename']
2475
+ = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);
2476
+
2477
+
2478
+ // ----- Skip empty file names
2479
+ // TBC : Can this be possible ? not checked in DescrParseAtt ?
2480
+ if ($p_filedescr_list[$j]['filename'] == "") {
2481
+ continue;
2482
+ }
2483
+
2484
+ // ----- Check the filename
2485
+ if ( ($p_filedescr_list[$j]['type'] != 'virtual_file')
2486
+ && (!file_exists($p_filedescr_list[$j]['filename']))) {
2487
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$p_filedescr_list[$j]['filename']."' does not exist");
2488
+ return PclZip::errorCode();
2489
+ }
2490
+
2491
+ // ----- Look if it is a file or a dir with no all path remove option
2492
+ // or a dir with all its path removed
2493
+ // if ( (is_file($p_filedescr_list[$j]['filename']))
2494
+ // || ( is_dir($p_filedescr_list[$j]['filename'])
2495
+ if ( ($p_filedescr_list[$j]['type'] == 'file')
2496
+ || ($p_filedescr_list[$j]['type'] == 'virtual_file')
2497
+ || ( ($p_filedescr_list[$j]['type'] == 'folder')
2498
+ && ( !isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])
2499
+ || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))
2500
+ ) {
2501
+
2502
+ // ----- Add the file
2503
+ $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header,
2504
+ $p_options);
2505
+ if ($v_result != 1) {
2506
+ return $v_result;
2507
+ }
2508
+
2509
+ // ----- Store the file infos
2510
+ $p_result_list[$v_nb++] = $v_header;
2511
+ }
2512
+ }
2513
+
2514
+ // ----- Return
2515
+ return $v_result;
2516
+ }
2517
+ // --------------------------------------------------------------------------------
2518
+
2519
+ // --------------------------------------------------------------------------------
2520
+ // Function : privAddFile()
2521
+ // Description :
2522
+ // Parameters :
2523
+ // Return Values :
2524
+ // --------------------------------------------------------------------------------
2525
+ function privAddFile($p_filedescr, &$p_header, &$p_options)
2526
+ {
2527
+ $v_result=1;
2528
+
2529
+ // ----- Working variable
2530
+ $p_filename = $p_filedescr['filename'];
2531
+
2532
+ // TBC : Already done in the fileAtt check ... ?
2533
+ if ($p_filename == "") {
2534
+ // ----- Error log
2535
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
2536
+
2537
+ // ----- Return
2538
+ return PclZip::errorCode();
2539
+ }
2540
+
2541
+ // ----- Look for a stored different filename
2542
+ /* TBC : Removed
2543
+ if (isset($p_filedescr['stored_filename'])) {
2544
+ $v_stored_filename = $p_filedescr['stored_filename'];
2545
+ }
2546
+ else {
2547
+ $v_stored_filename = $p_filedescr['stored_filename'];
2548
+ }
2549
+ */
2550
+
2551
+ // ----- Set the file properties
2552
+ clearstatcache();
2553
+ $p_header['version'] = 20;
2554
+ $p_header['version_extracted'] = 10;
2555
+ $p_header['flag'] = 0;
2556
+ $p_header['compression'] = 0;
2557
+ $p_header['crc'] = 0;
2558
+ $p_header['compressed_size'] = 0;
2559
+ $p_header['filename_len'] = strlen($p_filename);
2560
+ $p_header['extra_len'] = 0;
2561
+ $p_header['disk'] = 0;
2562
+ $p_header['internal'] = 0;
2563
+ $p_header['offset'] = 0;
2564
+ $p_header['filename'] = $p_filename;
2565
+ // TBC : Removed $p_header['stored_filename'] = $v_stored_filename;
2566
+ $p_header['stored_filename'] = $p_filedescr['stored_filename'];
2567
+ $p_header['extra'] = '';
2568
+ $p_header['status'] = 'ok';
2569
+ $p_header['index'] = -1;
2570
+
2571
+ // ----- Look for regular file
2572
+ if ($p_filedescr['type']=='file') {
2573
+ $p_header['external'] = 0x00000000;
2574
+ $p_header['size'] = filesize($p_filename);
2575
+ }
2576
+
2577
+ // ----- Look for regular folder
2578
+ else if ($p_filedescr['type']=='folder') {
2579
+ $p_header['external'] = 0x00000010;
2580
+ $p_header['mtime'] = filemtime($p_filename);
2581
+ $p_header['size'] = filesize($p_filename);
2582
+ }
2583
+
2584
+ // ----- Look for virtual file
2585
+ else if ($p_filedescr['type'] == 'virtual_file') {
2586
+ $p_header['external'] = 0x00000000;
2587
+ $p_header['size'] = strlen($p_filedescr['content']);
2588
+ }
2589
+
2590
+
2591
+ // ----- Look for filetime
2592
+ if (isset($p_filedescr['mtime'])) {
2593
+ $p_header['mtime'] = $p_filedescr['mtime'];
2594
+ }
2595
+ else if ($p_filedescr['type'] == 'virtual_file') {
2596
+ $p_header['mtime'] = time();
2597
+ }
2598
+ else {
2599
+ $p_header['mtime'] = filemtime($p_filename);
2600
+ }
2601
+
2602
+ // ------ Look for file comment
2603
+ if (isset($p_filedescr['comment'])) {
2604
+ $p_header['comment_len'] = strlen($p_filedescr['comment']);
2605
+ $p_header['comment'] = $p_filedescr['comment'];
2606
+ }
2607
+ else {
2608
+ $p_header['comment_len'] = 0;
2609
+ $p_header['comment'] = '';
2610
+ }
2611
+
2612
+ // ----- Look for pre-add callback
2613
+ if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
2614
+
2615
+ // ----- Generate a local information
2616
+ $v_local_header = array();
2617
+ $this->privConvertHeader2FileInfo($p_header, $v_local_header);
2618
+
2619
+ // ----- Call the callback
2620
+ // Here I do not use call_user_func() because I need to send a reference to the
2621
+ // header.
2622
+ // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
2623
+ $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
2624
+ if ($v_result == 0) {
2625
+ // ----- Change the file status
2626
+ $p_header['status'] = "skipped";
2627
+ $v_result = 1;
2628
+ }
2629
+
2630
+ // ----- Update the informations
2631
+ // Only some fields can be modified
2632
+ if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
2633
+ $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
2634
+ }
2635
+ }
2636
+
2637
+ // ----- Look for empty stored filename
2638
+ if ($p_header['stored_filename'] == "") {
2639
+ $p_header['status'] = "filtered";
2640
+ }
2641
+
2642
+ // ----- Check the path length
2643
+ if (strlen($p_header['stored_filename']) > 0xFF) {
2644
+ $p_header['status'] = 'filename_too_long';
2645
+ }
2646
+
2647
+ // ----- Look if no error, or file not skipped
2648
+ if ($p_header['status'] == 'ok') {
2649
+
2650
+ // ----- Look for a file
2651
+ if ($p_filedescr['type'] == 'file') {
2652
+ // ----- Look for using temporary file to zip
2653
+ if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
2654
+ && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
2655
+ || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
2656
+ && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) {
2657
+ $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
2658
+ if ($v_result < PCLZIP_ERR_NO_ERROR) {
2659
+ return $v_result;
2660
+ }
2661
+ }
2662
+
2663
+ // ----- Use "in memory" zip algo
2664
+ else {
2665
+
2666
+ // ----- Open the source file
2667
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
2668
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
2669
+ return PclZip::errorCode();
2670
+ }
2671
+
2672
+ // ----- Read the file content
2673
+ $v_content = @fread($v_file, $p_header['size']);
2674
+
2675
+ // ----- Close the file
2676
+ @fclose($v_file);
2677
+
2678
+ // ----- Calculate the CRC
2679
+ $p_header['crc'] = @crc32($v_content);
2680
+
2681
+ // ----- Look for no compression
2682
+ if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
2683
+ // ----- Set header parameters
2684
+ $p_header['compressed_size'] = $p_header['size'];
2685
+ $p_header['compression'] = 0;
2686
+ }
2687
+
2688
+ // ----- Look for normal compression
2689
+ else {
2690
+ // ----- Compress the content
2691
+ $v_content = @gzdeflate($v_content);
2692
+
2693
+ // ----- Set header parameters
2694
+ $p_header['compressed_size'] = strlen($v_content);
2695
+ $p_header['compression'] = 8;
2696
+ }
2697
+
2698
+ // ----- Call the header generation
2699
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2700
+ @fclose($v_file);
2701
+ return $v_result;
2702
+ }
2703
+
2704
+ // ----- Write the compressed (or not) content
2705
+ @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
2706
+
2707
+ }
2708
+
2709
+ }
2710
+
2711
+ // ----- Look for a virtual file (a file from string)
2712
+ else if ($p_filedescr['type'] == 'virtual_file') {
2713
+
2714
+ $v_content = $p_filedescr['content'];
2715
+
2716
+ // ----- Calculate the CRC
2717
+ $p_header['crc'] = @crc32($v_content);
2718
+
2719
+ // ----- Look for no compression
2720
+ if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
2721
+ // ----- Set header parameters
2722
+ $p_header['compressed_size'] = $p_header['size'];
2723
+ $p_header['compression'] = 0;
2724
+ }
2725
+
2726
+ // ----- Look for normal compression
2727
+ else {
2728
+ // ----- Compress the content
2729
+ $v_content = @gzdeflate($v_content);
2730
+
2731
+ // ----- Set header parameters
2732
+ $p_header['compressed_size'] = strlen($v_content);
2733
+ $p_header['compression'] = 8;
2734
+ }
2735
+
2736
+ // ----- Call the header generation
2737
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2738
+ @fclose($v_file);
2739
+ return $v_result;
2740
+ }
2741
+
2742
+ // ----- Write the compressed (or not) content
2743
+ @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
2744
+ }
2745
+
2746
+ // ----- Look for a directory
2747
+ else if ($p_filedescr['type'] == 'folder') {
2748
+ // ----- Look for directory last '/'
2749
+ if (@substr($p_header['stored_filename'], -1) != '/') {
2750
+ $p_header['stored_filename'] .= '/';
2751
+ }
2752
+
2753
+ // ----- Set the file properties
2754
+ $p_header['size'] = 0;
2755
+ //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked
2756
+ $p_header['external'] = 0x00000010; // Value for a folder : to be checked
2757
+
2758
+ // ----- Call the header generation
2759
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1)
2760
+ {
2761
+ return $v_result;
2762
+ }
2763
+ }
2764
+ }
2765
+
2766
+ // ----- Look for post-add callback
2767
+ if (isset($p_options[PCLZIP_CB_POST_ADD])) {
2768
+
2769
+ // ----- Generate a local information
2770
+ $v_local_header = array();
2771
+ $this->privConvertHeader2FileInfo($p_header, $v_local_header);
2772
+
2773
+ // ----- Call the callback
2774
+ // Here I do not use call_user_func() because I need to send a reference to the
2775
+ // header.
2776
+ // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
2777
+ $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
2778
+ if ($v_result == 0) {
2779
+ // ----- Ignored
2780
+ $v_result = 1;
2781
+ }
2782
+
2783
+ // ----- Update the informations
2784
+ // Nothing can be modified
2785
+ }
2786
+
2787
+ // ----- Return
2788
+ return $v_result;
2789
+ }
2790
+ // --------------------------------------------------------------------------------
2791
+
2792
+ // --------------------------------------------------------------------------------
2793
+ // Function : privAddFileUsingTempFile()
2794
+ // Description :
2795
+ // Parameters :
2796
+ // Return Values :
2797
+ // --------------------------------------------------------------------------------
2798
+ function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
2799
+ {
2800
+ $v_result=PCLZIP_ERR_NO_ERROR;
2801
+
2802
+ // ----- Working variable
2803
+ $p_filename = $p_filedescr['filename'];
2804
+
2805
+
2806
+ // ----- Open the source file
2807
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
2808
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
2809
+ return PclZip::errorCode();
2810
+ }
2811
+
2812
+ // ----- Creates a compressed temporary file
2813
+ $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
2814
+ if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
2815
+ fclose($v_file);
2816
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
2817
+ return PclZip::errorCode();
2818
+ }
2819
+
2820
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
2821
+ $v_size = filesize($p_filename);
2822
+ while ($v_size != 0) {
2823
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2824
+ $v_buffer = @fread($v_file, $v_read_size);
2825
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
2826
+ @gzputs($v_file_compressed, $v_buffer, $v_read_size);
2827
+ $v_size -= $v_read_size;
2828
+ }
2829
+
2830
+ // ----- Close the file
2831
+ @fclose($v_file);
2832
+ @gzclose($v_file_compressed);
2833
+
2834
+ // ----- Check the minimum file size
2835
+ if (filesize($v_gzip_temp_name) < 18) {
2836
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes');
2837
+ return PclZip::errorCode();
2838
+ }
2839
+
2840
+ // ----- Extract the compressed attributes
2841
+ if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
2842
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
2843
+ return PclZip::errorCode();
2844
+ }
2845
+
2846
+ // ----- Read the gzip file header
2847
+ $v_binary_data = @fread($v_file_compressed, 10);
2848
+ $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
2849
+
2850
+ // ----- Check some parameters
2851
+ $v_data_header['os'] = bin2hex($v_data_header['os']);
2852
+
2853
+ // ----- Read the gzip file footer
2854
+ @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8);
2855
+ $v_binary_data = @fread($v_file_compressed, 8);
2856
+ $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
2857
+
2858
+ // ----- Set the attributes
2859
+ $p_header['compression'] = ord($v_data_header['cm']);
2860
+ //$p_header['mtime'] = $v_data_header['mtime'];
2861
+ $p_header['crc'] = $v_data_footer['crc'];
2862
+ $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18;
2863
+
2864
+ // ----- Close the file
2865
+ @fclose($v_file_compressed);
2866
+
2867
+ // ----- Call the header generation
2868
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2869
+ return $v_result;
2870
+ }
2871
+
2872
+ // ----- Add the compressed data
2873
+ if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0)
2874
+ {
2875
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
2876
+ return PclZip::errorCode();
2877
+ }
2878
+
2879
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
2880
+ fseek($v_file_compressed, 10);
2881
+ $v_size = $p_header['compressed_size'];
2882
+ while ($v_size != 0)
2883
+ {
2884
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2885
+ $v_buffer = @fread($v_file_compressed, $v_read_size);
2886
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
2887
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
2888
+ $v_size -= $v_read_size;
2889
+ }
2890
+
2891
+ // ----- Close the file
2892
+ @fclose($v_file_compressed);
2893
+
2894
+ // ----- Unlink the temporary file
2895
+ @unlink($v_gzip_temp_name);
2896
+
2897
+ // ----- Return
2898
+ return $v_result;
2899
+ }
2900
+ // --------------------------------------------------------------------------------
2901
+
2902
+ // --------------------------------------------------------------------------------
2903
+ // Function : privCalculateStoredFilename()
2904
+ // Description :
2905
+ // Based on file descriptor properties and global options, this method
2906
+ // calculate the filename that will be stored in the archive.
2907
+ // Parameters :
2908
+ // Return Values :
2909
+ // --------------------------------------------------------------------------------
2910
+ function privCalculateStoredFilename(&$p_filedescr, &$p_options)
2911
+ {
2912
+ $v_result=1;
2913
+
2914
+ // ----- Working variables
2915
+ $p_filename = $p_filedescr['filename'];
2916
+ if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
2917
+ $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
2918
+ }
2919
+ else {
2920
+ $p_add_dir = '';
2921
+ }
2922
+ if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
2923
+ $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
2924
+ }
2925
+ else {
2926
+ $p_remove_dir = '';
2927
+ }
2928
+ if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
2929
+ $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
2930
+ }
2931
+ else {
2932
+ $p_remove_all_dir = 0;
2933
+ }
2934
+
2935
+
2936
+ // ----- Look for full name change
2937
+ if (isset($p_filedescr['new_full_name'])) {
2938
+ // ----- Remove drive letter if any
2939
+ $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
2940
+ }
2941
+
2942
+ // ----- Look for path and/or short name change
2943
+ else {
2944
+
2945
+ // ----- Look for short name change
2946
+ // Its when we cahnge just the filename but not the path
2947
+ if (isset($p_filedescr['new_short_name'])) {
2948
+ $v_path_info = pathinfo($p_filename);
2949
+ $v_dir = '';
2950
+ if ($v_path_info['dirname'] != '') {
2951
+ $v_dir = $v_path_info['dirname'].'/';
2952
+ }
2953
+ $v_stored_filename = $v_dir.$p_filedescr['new_short_name'];
2954
+ }
2955
+ else {
2956
+ // ----- Calculate the stored filename
2957
+ $v_stored_filename = $p_filename;
2958
+ }
2959
+
2960
+ // ----- Look for all path to remove
2961
+ if ($p_remove_all_dir) {
2962
+ $v_stored_filename = basename($p_filename);
2963
+ }
2964
+ // ----- Look for partial path remove
2965
+ else if ($p_remove_dir != "") {
2966
+ if (substr($p_remove_dir, -1) != '/')
2967
+ $p_remove_dir .= "/";
2968
+
2969
+ if ( (substr($p_filename, 0, 2) == "./")
2970
+ || (substr($p_remove_dir, 0, 2) == "./")) {
2971
+
2972
+ if ( (substr($p_filename, 0, 2) == "./")
2973
+ && (substr($p_remove_dir, 0, 2) != "./")) {
2974
+ $p_remove_dir = "./".$p_remove_dir;
2975
+ }
2976
+ if ( (substr($p_filename, 0, 2) != "./")
2977
+ && (substr($p_remove_dir, 0, 2) == "./")) {
2978
+ $p_remove_dir = substr($p_remove_dir, 2);
2979
+ }
2980
+ }
2981
+
2982
+ $v_compare = PclZipUtilPathInclusion($p_remove_dir,
2983
+ $v_stored_filename);
2984
+ if ($v_compare > 0) {
2985
+ if ($v_compare == 2) {
2986
+ $v_stored_filename = "";
2987
+ }
2988
+ else {
2989
+ $v_stored_filename = substr($v_stored_filename,
2990
+ strlen($p_remove_dir));
2991
+ }
2992
+ }
2993
+ }
2994
+
2995
+ // ----- Remove drive letter if any
2996
+ $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
2997
+
2998
+ // ----- Look for path to add
2999
+ if ($p_add_dir != "") {
3000
+ if (substr($p_add_dir, -1) == "/")
3001
+ $v_stored_filename = $p_add_dir.$v_stored_filename;
3002
+ else
3003
+ $v_stored_filename = $p_add_dir."/".$v_stored_filename;
3004
+ }
3005
+ }
3006
+
3007
+ // ----- Filename (reduce the path of stored name)
3008
+ $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
3009
+ $p_filedescr['stored_filename'] = $v_stored_filename;
3010
+
3011
+ // ----- Return
3012
+ return $v_result;
3013
+ }
3014
+ // --------------------------------------------------------------------------------
3015
+
3016
+ // --------------------------------------------------------------------------------
3017
+ // Function : privWriteFileHeader()
3018
+ // Description :
3019
+ // Parameters :
3020
+ // Return Values :
3021
+ // --------------------------------------------------------------------------------
3022
+ function privWriteFileHeader(&$p_header)
3023
+ {
3024
+ $v_result=1;
3025
+
3026
+ // ----- Store the offset position of the file
3027
+ $p_header['offset'] = ftell($this->zip_fd);
3028
+
3029
+ // ----- Transform UNIX mtime to DOS format mdate/mtime
3030
+ $v_date = getdate($p_header['mtime']);
3031
+ $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
3032
+ $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
3033
+
3034
+ // ----- Packed data
3035
+ $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50,
3036
+ $p_header['version_extracted'], $p_header['flag'],
3037
+ $p_header['compression'], $v_mtime, $v_mdate,
3038
+ $p_header['crc'], $p_header['compressed_size'],
3039
+ $p_header['size'],
3040
+ strlen($p_header['stored_filename']),
3041
+ $p_header['extra_len']);
3042
+
3043
+ // ----- Write the first 148 bytes of the header in the archive
3044
+ fputs($this->zip_fd, $v_binary_data, 30);
3045
+
3046
+ // ----- Write the variable fields
3047
+ if (strlen($p_header['stored_filename']) != 0)
3048
+ {
3049
+ fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
3050
+ }
3051
+ if ($p_header['extra_len'] != 0)
3052
+ {
3053
+ fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
3054
+ }
3055
+
3056
+ // ----- Return
3057
+ return $v_result;
3058
+ }
3059
+ // --------------------------------------------------------------------------------
3060
+