PHPExcel_Reader_Excel5   F
last analyzed

Complexity

Total Complexity 1263

Size/Duplication

Total Lines 6813
Duplicated Lines 10.8 %

Coupling/Cohesion

Components 1
Dependencies 38

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 736
loc 6813
rs 0.5217
wmc 1263
lcom 1
cbo 38

121 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getReadDataOnly() 0 4 1
A setReadDataOnly() 0 5 1
A getLoadSheetsOnly() 0 4 1
A setLoadSheetsOnly() 0 6 2
A setLoadAllSheets() 0 5 1
A getReadFilter() 0 3 1
A setReadFilter() 0 4 1
A canRead() 0 19 3
C listWorksheetNames() 10 41 8
D listWorksheetInfo() 10 86 17
F load() 24 484 127
A _loadOLE() 0 19 1
D _readSummaryInformation() 10 155 28
D _readDocumentSummaryInformation() 10 154 27
A _readDefault() 8 8 1
B _readNote() 0 58 5
B _readTextObject() 0 35 2
C _readBof() 0 35 7
A _readFilepass() 10 10 1
A _readCodepage() 0 13 1
A _readDateMode() 0 14 2
F _readFont() 5 82 13
A _readFormat() 6 22 3
F _readXf() 24 278 47
D _readXfExt() 120 172 27
B _readStyle() 0 36 4
A _readPalette() 0 19 3
B _readSheet() 7 38 6
B _readExternalBook() 0 59 6
B _readExternName() 0 30 2
B _readExternSheet() 0 24 3
A _readDefinedName() 0 50 3
A _readMsoDrawingGroup() 10 10 1
F _readSst() 0 179 23
A _readPrintGridlines() 0 14 3
A _readDefaultRowHeight() 0 13 1
A _readSheetPr() 0 22 1
B _readHorizontalPageBreaks() 24 24 4
B _readVerticalPageBreaks() 23 23 4
B _readHeader() 23 23 4
B _readFooter() 22 22 4
A _readHcenter() 0 15 2
A _readVcenter() 0 15 2
A _readLeftMargin() 0 13 2
A _readRightMargin() 0 13 2
A _readTopMargin() 0 13 2
A _readBottomMargin() 0 13 2
B _readPageSetup() 0 52 5
A _readProtect() 0 18 2
A _readScenProtect() 0 19 2
A _readObjectProtect() 0 19 2
A _readPassword() 0 14 2
A _readDefColWidth() 0 14 2
B _readColInfo() 0 47 5
A _readRow() 0 57 4
B _readRk() 34 34 4
C _readLabelSst() 0 68 12
B _readMulRk() 0 45 5
B _readNumber() 32 32 4
F _readFormula() 18 134 24
B _readSharedFmla() 0 24 1
A _readString() 0 18 2
B _readBoolErr() 0 49 6
B _readMulBlank() 4 30 5
B _readLabel() 7 38 5
B _readBlank() 9 27 4
A _readMsoDrawing() 10 10 1
B _readObj() 0 40 3
B _readWindow2() 0 31 2
A _readScl() 0 17 1
A _readPane() 0 23 3
B _readSelection() 0 46 5
B _includeCellRangeFiltered() 0 18 5
B _readMergedCells() 0 17 5
F _readHyperLink() 0 171 19
A _readDataValidations() 8 8 1
F _readDataValidation() 25 155 30
B _readSheetLayout() 0 35 4
B _readSheetProtection() 0 94 3
B _readRangeProtection() 0 56 6
B _readImData() 0 76 6
B _readContinue() 0 43 4
B _getSplicedRecordData() 0 32 2
B _getFormulaFromStructure() 0 30 2
A _getFormulaFromData() 0 17 3
F _createFormulaFromTokens() 16 154 63
F _getNextToken() 57 556 333
A _readBIFF8CellAddress() 0 21 3
B _readBIFF8CellAddressB() 7 33 5
B _readBIFF5CellRangeAddressFixed() 0 28 5
B _readBIFF8CellRangeAddressFixed() 0 28 5
B _readBIFF8CellRangeAddress() 0 43 5
C _readBIFF8CellRangeAddressB() 36 72 10
A _readBIFF8CellRangeAddressList() 19 19 2
A _readBIFF5CellRangeAddressList() 19 19 2
C _readSheetRangeByRefIndex() 0 46 7
B _readBIFF8ConstantArray() 0 29 3
C _readBIFF8Constant() 0 41 7
A _readRGB() 0 16 1
A _readByteStringShort() 13 13 1
A _readByteStringLong() 14 14 1
A _readUnicodeStringShort() 14 14 1
A _readUnicodeStringLong() 14 14 1
B _readUnicodeString() 0 25 3
A _UTF8toExcelDoubleQuoted() 0 4 1
A _extractNumber() 0 22 3
B _GetIEEE754() 0 24 4
A _encodeUTF16() 0 8 2
A _uncompressByteString() 0 10 2
A _decodeCodepage() 0 4 1
A _GetInt2d() 0 4 1
A _GetInt4d() 14 14 2
B _readColor() 0 20 6
B _mapBorderStyle() 20 20 15
D _mapFillPattern() 0 25 20
B _mapErrorCode() 0 13 8
B _mapBuiltInColor() 0 16 11
C _mapColorBIFF5() 0 62 57
C _mapColor() 0 62 57
A _parseRichText() 0 7 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like PHPExcel_Reader_Excel5 often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PHPExcel_Reader_Excel5, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * PHPExcel
4
 *
5
 * Copyright (c) 2006 - 2012 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 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
24
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
25
 * @version    1.7.7, 2012-05-19
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 View Code Duplication
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 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
77
 */
78
class PHPExcel_Reader_Excel5 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_UNKNOWN				= 0xffff;
160
161
162
	/**
163
	 * Read data only?
164
	 * Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
165
	 *		or whether it should read both data and formatting
166
	 *
167
	 * @var	boolean
168
	 */
169
	private $_readDataOnly = false;
170
171
	/**
172
	 * Restrict which sheets should be loaded?
173
	 * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
174
	 *
175
	 * @var	array of string
176
	 */
177
	private $_loadSheetsOnly = null;
178
179
	/**
180
	 * PHPExcel_Reader_IReadFilter instance
181
	 *
182
	 * @var PHPExcel_Reader_IReadFilter
183
	 */
184
	private $_readFilter = null;
185
186
	/**
187
	 * Summary Information stream data.
188
	 *
189
	 * @var string
190
	 */
191
	private $_summaryInformation;
192
193
	/**
194
	 * Extended Summary Information stream data.
195
	 *
196
	 * @var string
197
	 */
198
	private $_documentSummaryInformation;
199
200
	/**
201
	 * User-Defined Properties stream data.
202
	 *
203
	 * @var string
204
	 */
205
	private $_userDefinedProperties;
0 ignored issues
show
Unused Code introduced by
The property $_userDefinedProperties is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
206
207
	/**
208
	 * Workbook stream data. (Includes workbook globals substream as well as sheet substreams)
209
	 *
210
	 * @var string
211
	 */
212
	private $_data;
213
214
	/**
215
	 * Size in bytes of $this->_data
216
	 *
217
	 * @var int
218
	 */
219
	private $_dataSize;
220
221
	/**
222
	 * Current position in stream
223
	 *
224
	 * @var integer
225
	 */
226
	private $_pos;
227
228
	/**
229
	 * Workbook to be returned by the reader.
230
	 *
231
	 * @var PHPExcel
232
	 */
233
	private $_phpExcel;
234
235
	/**
236
	 * Worksheet that is currently being built by the reader.
237
	 *
238
	 * @var PHPExcel_Worksheet
239
	 */
240
	private $_phpSheet;
241
242
	/**
243
	 * BIFF version
244
	 *
245
	 * @var int
246
	 */
247
	private $_version;
248
249
	/**
250
	 * Codepage set in the Excel file being read. Only important for BIFF5 (Excel 5.0 - Excel 95)
251
	 * For BIFF8 (Excel 97 - Excel 2003) this will always have the value 'UTF-16LE'
252
	 *
253
	 * @var string
254
	 */
255
	private $_codepage;
256
257
	/**
258
	 * Shared formats
259
	 *
260
	 * @var array
261
	 */
262
	private $_formats;
263
264
	/**
265
	 * Shared fonts
266
	 *
267
	 * @var array
268
	 */
269
	private $_objFonts;
270
271
	/**
272
	 * Color palette
273
	 *
274
	 * @var array
275
	 */
276
	private $_palette;
277
278
	/**
279
	 * Worksheets
280
	 *
281
	 * @var array
282
	 */
283
	private $_sheets;
284
285
	/**
286
	 * External books
287
	 *
288
	 * @var array
289
	 */
290
	private $_externalBooks;
291
292
	/**
293
	 * REF structures. Only applies to BIFF8.
294
	 *
295
	 * @var array
296
	 */
297
	private $_ref;
298
299
	/**
300
	 * External names
301
	 *
302
	 * @var array
303
	 */
304
	private $_externalNames;
305
306
	/**
307
	 * Defined names
308
	 *
309
	 * @var array
310
	 */
311
	private $_definedname;
312
313
	/**
314
	 * Shared strings. Only applies to BIFF8.
315
	 *
316
	 * @var array
317
	 */
318
	private $_sst;
319
320
	/**
321
	 * Panes are frozen? (in sheet currently being read). See WINDOW2 record.
322
	 *
323
	 * @var boolean
324
	 */
325
	private $_frozen;
326
327
	/**
328
	 * Fit printout to number of pages? (in sheet currently being read). See SHEETPR record.
329
	 *
330
	 * @var boolean
331
	 */
332
	private $_isFitToPages;
333
334
	/**
335
	 * Objects. One OBJ record contributes with one entry.
336
	 *
337
	 * @var array
338
	 */
339
	private $_objs;
340
341
	/**
342
	 * Text Objects. One TXO record corresponds with one entry.
343
	 *
344
	 * @var array
345
	 */
346
	private $_textObjects;
347
348
	/**
349
	 * Cell Annotations (BIFF8)
350
	 *
351
	 * @var array
352
	 */
353
	private $_cellNotes;
354
355
	/**
356
	 * The combined MSODRAWINGGROUP data
357
	 *
358
	 * @var string
359
	 */
360
	private $_drawingGroupData;
361
362
	/**
363
	 * The combined MSODRAWING data (per sheet)
364
	 *
365
	 * @var string
366
	 */
367
	private $_drawingData;
368
369
	/**
370
	 * Keep track of XF index
371
	 *
372
	 * @var int
373
	 */
374
	private $_xfIndex;
375
376
	/**
377
	 * Mapping of XF index (that is a cell XF) to final index in cellXf collection
378
	 *
379
	 * @var array
380
	 */
381
	private $_mapCellXfIndex;
382
383
	/**
384
	 * Mapping of XF index (that is a style XF) to final index in cellStyleXf collection
385
	 *
386
	 * @var array
387
	 */
388
	private $_mapCellStyleXfIndex;
389
390
	/**
391
	 * The shared formulas in a sheet. One SHAREDFMLA record contributes with one value.
392
	 *
393
	 * @var array
394
	 */
395
	private $_sharedFormulas;
396
397
	/**
398
	 * The shared formula parts in a sheet. One FORMULA record contributes with one value if it
399
	 * refers to a shared formula.
400
	 *
401
	 * @var array
402
	 */
403
	private $_sharedFormulaParts;
404
405
406
	/**
407
	 * Create a new PHPExcel_Reader_Excel5 instance
408
	 */
409
	public function __construct() {
410
		$this->_readFilter = new PHPExcel_Reader_DefaultReadFilter();
411
	}
412
413
414
	/**
415
	 * Read data only?
416
	 *		If this is true, then the Reader will only read data values for cells, it will not read any formatting information.
417
	 *		If false (the default) it will read data and formatting.
418
	 *
419
	 * @return	boolean
420
	 */
421
	public function getReadDataOnly()
422
	{
423
		return $this->_readDataOnly;
424
	}
425
426
427
	/**
428
	 * Set read data only
429
	 *		Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
430
	 *		Set to false (the default) to advise the Reader to read both data and formatting for cells.
431
	 *
432
	 * @param	boolean	$pValue
433
	 *
434
	 * @return	PHPExcel_Reader_Excel5
435
	 */
436
	public function setReadDataOnly($pValue = false)
437
	{
438
		$this->_readDataOnly = $pValue;
439
		return $this;
440
	}
441
442
443
	/**
444
	 * Get which sheets to load
445
	 *		Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
446
	 *			indicating that all worksheets in the workbook should be loaded.
447
	 *
448
	 * @return mixed
449
	 */
450
	public function getLoadSheetsOnly()
451
	{
452
		return $this->_loadSheetsOnly;
453
	}
454
455
456
	/**
457
	 * Set which sheets to load
458
	 *
459
	 * @param mixed $value
460
	 *		This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name.
461
	 *		If NULL, then it tells the Reader to read all worksheets in the workbook
462
	 *
463
	 * @return PHPExcel_Reader_Excel5
464
	 */
465
	public function setLoadSheetsOnly($value = null)
466
	{
467
		$this->_loadSheetsOnly = is_array($value) ?
468
			$value : array($value);
469
		return $this;
470
	}
471
472
473
	/**
474
	 * Set all sheets to load
475
	 *		Tells the Reader to load all worksheets from the workbook.
476
	 *
477
	 * @return	PHPExcel_Reader_Excel5
478
	 */
479
	public function setLoadAllSheets()
480
	{
481
		$this->_loadSheetsOnly = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $_loadSheetsOnly.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
482
		return $this;
483
	}
484
485
486
	/**
487
	 * Read filter
488
	 *
489
	 * @return PHPExcel_Reader_IReadFilter
490
	 */
491
	public function getReadFilter() {
492
		return $this->_readFilter;
493
	}
494
495
496
	/**
497
	 * Set read filter
498
	 *
499
	 * @param PHPExcel_Reader_IReadFilter $pValue
500
	 * @return PHPExcel_Reader_Excel5
501
	 */
502
	public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue) {
503
		$this->_readFilter = $pValue;
504
		return $this;
505
	}
506
507
508
	/**
509
	 * Can the current PHPExcel_Reader_IReader read the file?
510
	 *
511
	 * @param 	string 		$pFileName
0 ignored issues
show
Documentation introduced by
There is no parameter named $pFileName. Did you maybe mean $pFilename?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
512
	 * @return 	boolean
513
	 * @throws Exception
514
	 */
515
	public function canRead($pFilename)
516
	{
517
		// Check if file exists
518
		if (!file_exists($pFilename)) {
519
			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
520
		}
521
522
		try {
523
			// Use ParseXL for the hard work.
524
			$ole = new PHPExcel_Shared_OLERead();
525
526
			// get excel data
527
			$res = $ole->read($pFilename);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $res is correct as $ole->read($pFilename) (which targets PHPExcel_Shared_OLERead::read()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
528
			return true;
529
530
		} catch (Exception $e) {
531
			return false;
532
		}
533
	}
534
535
536
	/**
537
	 * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
538
	 *
539
	 * @param 	string 		$pFilename
540
	 * @throws 	Exception
541
	 */
542
	public function listWorksheetNames($pFilename)
543
	{
544
		// Check if file exists
545
		if (!file_exists($pFilename)) {
546
			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
547
		}
548
549
		$worksheetNames = array();
550
551
		// Read the OLE file
552
		$this->_loadOLE($pFilename);
553
554
		// total byte size of Excel data (workbook global substream + sheet substreams)
555
		$this->_dataSize = strlen($this->_data);
556
557
		$this->_pos		= 0;
558
		$this->_sheets	= array();
559
560
		// Parse Workbook Global Substream
561 View Code Duplication
		while ($this->_pos < $this->_dataSize) {
562
			$code = self::_GetInt2d($this->_data, $this->_pos);
563
564
			switch ($code) {
565
				case self::XLS_Type_BOF:	$this->_readBof();		break;
566
				case self::XLS_Type_SHEET:	$this->_readSheet();	break;
567
				case self::XLS_Type_EOF:	$this->_readDefault();	break 2;
568
				default:					$this->_readDefault();	break;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
569
			}
570
		}
571
572
		foreach ($this->_sheets as $sheet) {
573
			if ($sheet['sheetType'] != 0x00) {
574
				// 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
575
				continue;
576
			}
577
578
			$worksheetNames[] = $sheet['name'];
579
		}
580
581
		return $worksheetNames;
582
	}
583
584
585
	/**
586
	 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
587
	 *
588
	 * @param   string     $pFilename
589
	 * @throws   Exception
590
	 */
591
	public function listWorksheetInfo($pFilename)
592
	{
593
		// Check if file exists
594
		if (!file_exists($pFilename)) {
595
			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
596
		}
597
598
		$worksheetInfo = array();
599
600
		// Read the OLE file
601
		$this->_loadOLE($pFilename);
602
603
		// total byte size of Excel data (workbook global substream + sheet substreams)
604
		$this->_dataSize = strlen($this->_data);
605
606
		// initialize
607
		$this->_pos    = 0;
608
		$this->_sheets = array();
609
610
		// Parse Workbook Global Substream
611 View Code Duplication
		while ($this->_pos < $this->_dataSize) {
612
			$code = self::_GetInt2d($this->_data, $this->_pos);
613
614
			switch ($code) {
615
				case self::XLS_Type_BOF:        $this->_readBof();        break;
616
				case self::XLS_Type_SHEET:      $this->_readSheet();      break;
617
				case self::XLS_Type_EOF:        $this->_readDefault();    break 2;
618
				default:                        $this->_readDefault();    break;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
619
			}
620
		}
621
622
		// Parse the individual sheets
623
		foreach ($this->_sheets as $sheet) {
624
625
			if ($sheet['sheetType'] != 0x00) {
626
				// 0x00: Worksheet
627
				// 0x02: Chart
628
				// 0x06: Visual Basic module
629
				continue;
630
			}
631
632
			$tmpInfo = array();
633
			$tmpInfo['worksheetName'] = $sheet['name'];
634
			$tmpInfo['lastColumnLetter'] = 'A';
635
			$tmpInfo['lastColumnIndex'] = 0;
636
			$tmpInfo['totalRows'] = 0;
637
			$tmpInfo['totalColumns'] = 0;
638
639
			$this->_pos = $sheet['offset'];
640
641
			while ($this->_pos <= $this->_dataSize - 4) {
642
				$code = self::_GetInt2d($this->_data, $this->_pos);
643
644
				switch ($code) {
645
					case self::XLS_Type_RK:
646
					case self::XLS_Type_LABELSST:
647
					case self::XLS_Type_NUMBER:
648
					case self::XLS_Type_FORMULA:
649
					case self::XLS_Type_BOOLERR:
650
					case self::XLS_Type_LABEL:
651
						$length = self::_GetInt2d($this->_data, $this->_pos + 2);
652
						$recordData = substr($this->_data, $this->_pos + 4, $length);
653
654
						// move stream pointer to next record
655
						$this->_pos += 4 + $length;
656
657
						$rowIndex = self::_GetInt2d($recordData, 0) + 1;
658
						$columnIndex = self::_GetInt2d($recordData, 2);
659
660
						$tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
661
						$tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
662
						break;
663
					case self::XLS_Type_BOF:      $this->_readBof();          break;
664
					case self::XLS_Type_EOF:      $this->_readDefault();      break 2;
665
					default:                      $this->_readDefault();      break;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
666
				}
667
			}
668
669
			$tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
670
			$tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
671
672
			$worksheetInfo[] = $tmpInfo;
673
		}
674
675
		return $worksheetInfo;
676
	}
677
678
679
	/**
680
	 * Loads PHPExcel from file
681
	 *
682
	 * @param 	string 		$pFilename
683
	 * @return 	PHPExcel
684
	 * @throws 	Exception
685
	 */
686
	public function load($pFilename)
687
	{
688
		// Read the OLE file
689
		$this->_loadOLE($pFilename);
690
691
		// Initialisations
692
		$this->_phpExcel = new PHPExcel;
693
		$this->_phpExcel->removeSheetByIndex(0); // remove 1st sheet
694
		if (!$this->_readDataOnly) {
695
			$this->_phpExcel->removeCellStyleXfByIndex(0); // remove the default style
696
			$this->_phpExcel->removeCellXfByIndex(0); // remove the default style
697
		}
698
699
		// Read the summary information stream (containing meta data)
700
		$this->_readSummaryInformation();
701
702
		// Read the Additional document summary information stream (containing application-specific meta data)
703
		$this->_readDocumentSummaryInformation();
704
705
		// total byte size of Excel data (workbook global substream + sheet substreams)
706
		$this->_dataSize = strlen($this->_data);
707
708
		// initialize
709
		$this->_pos					= 0;
710
		$this->_codepage			= 'CP1252';
711
		$this->_formats				= array();
712
		$this->_objFonts			= array();
713
		$this->_palette				= array();
714
		$this->_sheets				= array();
715
		$this->_externalBooks		= array();
716
		$this->_ref					= array();
717
		$this->_definedname			= array();
718
		$this->_sst					= array();
719
		$this->_drawingGroupData	= '';
720
		$this->_xfIndex				= '';
0 ignored issues
show
Documentation Bug introduced by
The property $_xfIndex was declared of type integer, but '' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
721
		$this->_mapCellXfIndex		= array();
722
		$this->_mapCellStyleXfIndex	= array();
723
724
		// Parse Workbook Global Substream
725
		while ($this->_pos < $this->_dataSize) {
726
			$code = self::_GetInt2d($this->_data, $this->_pos);
727
728
			switch ($code) {
729
				case self::XLS_Type_BOF:			$this->_readBof();				break;
730
				case self::XLS_Type_FILEPASS:		$this->_readFilepass();			break;
731
				case self::XLS_Type_CODEPAGE:		$this->_readCodepage();			break;
732
				case self::XLS_Type_DATEMODE:		$this->_readDateMode();			break;
733
				case self::XLS_Type_FONT:			$this->_readFont();				break;
734
				case self::XLS_Type_FORMAT:			$this->_readFormat();			break;
735
				case self::XLS_Type_XF:				$this->_readXf();				break;
736
				case self::XLS_Type_XFEXT:			$this->_readXfExt();			break;
737
				case self::XLS_Type_STYLE:			$this->_readStyle();			break;
738
				case self::XLS_Type_PALETTE:		$this->_readPalette();			break;
739
				case self::XLS_Type_SHEET:			$this->_readSheet();			break;
740
				case self::XLS_Type_EXTERNALBOOK:	$this->_readExternalBook();		break;
741
				case self::XLS_Type_EXTERNNAME:		$this->_readExternName();		break;
742
				case self::XLS_Type_EXTERNSHEET:	$this->_readExternSheet();		break;
743
				case self::XLS_Type_DEFINEDNAME:	$this->_readDefinedName();		break;
744
				case self::XLS_Type_MSODRAWINGGROUP:	$this->_readMsoDrawingGroup();	break;
745
				case self::XLS_Type_SST:			$this->_readSst();				break;
746
				case self::XLS_Type_EOF:			$this->_readDefault();			break 2;
747
				default:							$this->_readDefault();			break;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
748
			}
749
		}
750
751
		// Resolve indexed colors for font, fill, and border colors
752
		// Cannot be resolved already in XF record, because PALETTE record comes afterwards
753
		if (!$this->_readDataOnly) {
754
			foreach ($this->_objFonts as $objFont) {
755 View Code Duplication
				if (isset($objFont->colorIndex)) {
756
					$color = self::_readColor($objFont->colorIndex,$this->_palette,$this->_version);
757
					$objFont->getColor()->setRGB($color['rgb']);
758
				}
759
			}
760
761
			foreach ($this->_phpExcel->getCellXfCollection() as $objStyle) {
762
				// fill start and end color
763
				$fill = $objStyle->getFill();
764
765
				if (isset($fill->startcolorIndex)) {
766
					$startColor = self::_readColor($fill->startcolorIndex,$this->_palette,$this->_version);
0 ignored issues
show
Bug introduced by
The property startcolorIndex does not seem to exist in PHPExcel_Style_Fill.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
767
					$fill->getStartColor()->setRGB($startColor['rgb']);
768
				}
769
770
				if (isset($fill->endcolorIndex)) {
771
					$endColor = self::_readColor($fill->endcolorIndex,$this->_palette,$this->_version);
0 ignored issues
show
Bug introduced by
The property endcolorIndex does not seem to exist in PHPExcel_Style_Fill.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
772
					$fill->getEndColor()->setRGB($endColor['rgb']);
773
				}
774
775
				// border colors
776
				$top      = $objStyle->getBorders()->getTop();
777
				$right    = $objStyle->getBorders()->getRight();
778
				$bottom   = $objStyle->getBorders()->getBottom();
779
				$left     = $objStyle->getBorders()->getLeft();
780
				$diagonal = $objStyle->getBorders()->getDiagonal();
781
782 View Code Duplication
				if (isset($top->colorIndex)) {
783
					$borderTopColor = self::_readColor($top->colorIndex,$this->_palette,$this->_version);
0 ignored issues
show
Bug introduced by
The property colorIndex does not seem to exist in PHPExcel_Style_Border.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
784
					$top->getColor()->setRGB($borderTopColor['rgb']);
785
				}
786
787 View Code Duplication
				if (isset($right->colorIndex)) {
788
					$borderRightColor = self::_readColor($right->colorIndex,$this->_palette,$this->_version);
789
					$right->getColor()->setRGB($borderRightColor['rgb']);
790
				}
791
792 View Code Duplication
				if (isset($bottom->colorIndex)) {
793
					$borderBottomColor = self::_readColor($bottom->colorIndex,$this->_palette,$this->_version);
794
					$bottom->getColor()->setRGB($borderBottomColor['rgb']);
795
				}
796
797 View Code Duplication
				if (isset($left->colorIndex)) {
798
					$borderLeftColor = self::_readColor($left->colorIndex,$this->_palette,$this->_version);
799
					$left->getColor()->setRGB($borderLeftColor['rgb']);
800
				}
801
802 View Code Duplication
				if (isset($diagonal->colorIndex)) {
803
					$borderDiagonalColor = self::_readColor($diagonal->colorIndex,$this->_palette,$this->_version);
804
					$diagonal->getColor()->setRGB($borderDiagonalColor['rgb']);
805
				}
806
			}
807
		}
808
809
		// treat MSODRAWINGGROUP records, workbook-level Escher
810
		if (!$this->_readDataOnly && $this->_drawingGroupData) {
811
			$escherWorkbook = new PHPExcel_Shared_Escher();
812
			$reader = new PHPExcel_Reader_Excel5_Escher($escherWorkbook);
813
			$escherWorkbook = $reader->load($this->_drawingGroupData);
814
815
			// debug Escher stream
816
			//$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
817
			//$debug->load($this->_drawingGroupData);
818
		}
819
820
		// Parse the individual sheets
821
		foreach ($this->_sheets as $sheet) {
822
823
			if ($sheet['sheetType'] != 0x00) {
824
				// 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
825
				continue;
826
			}
827
828
			// check if sheet should be skipped
829
			if (isset($this->_loadSheetsOnly) && !in_array($sheet['name'], $this->_loadSheetsOnly)) {
830
				continue;
831
			}
832
833
			// add sheet to PHPExcel object
834
			$this->_phpSheet = $this->_phpExcel->createSheet();
835
			//	Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
836
			//		cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
837
			//		name in line with the formula, not the reverse
838
			$this->_phpSheet->setTitle($sheet['name'],false);
839
			$this->_phpSheet->setSheetState($sheet['sheetState']);
840
841
			$this->_pos = $sheet['offset'];
842
843
			// Initialize isFitToPages. May change after reading SHEETPR record.
844
			$this->_isFitToPages = false;
845
846
			// Initialize drawingData
847
			$this->_drawingData = '';
848
849
			// Initialize objs
850
			$this->_objs = array();
851
852
			// Initialize shared formula parts
853
			$this->_sharedFormulaParts = array();
854
855
			// Initialize shared formulas
856
			$this->_sharedFormulas = array();
857
858
			// Initialize text objs
859
			$this->_textObjects = array();
860
861
			// Initialize cell annotations
862
			$this->_cellNotes = array();
863
			$this->textObjRef = -1;
864
865
			while ($this->_pos <= $this->_dataSize - 4) {
866
				$code = self::_GetInt2d($this->_data, $this->_pos);
867
868
				switch ($code) {
869
					case self::XLS_Type_BOF:					$this->_readBof();						break;
870
					case self::XLS_Type_PRINTGRIDLINES:			$this->_readPrintGridlines();			break;
871
					case self::XLS_Type_DEFAULTROWHEIGHT:		$this->_readDefaultRowHeight();			break;
872
					case self::XLS_Type_SHEETPR:				$this->_readSheetPr();					break;
873
					case self::XLS_Type_HORIZONTALPAGEBREAKS:	$this->_readHorizontalPageBreaks();		break;
874
					case self::XLS_Type_VERTICALPAGEBREAKS:		$this->_readVerticalPageBreaks();		break;
875
					case self::XLS_Type_HEADER:					$this->_readHeader();					break;
876
					case self::XLS_Type_FOOTER:					$this->_readFooter();					break;
877
					case self::XLS_Type_HCENTER:				$this->_readHcenter();					break;
878
					case self::XLS_Type_VCENTER:				$this->_readVcenter();					break;
879
					case self::XLS_Type_LEFTMARGIN:				$this->_readLeftMargin();				break;
880
					case self::XLS_Type_RIGHTMARGIN:			$this->_readRightMargin();				break;
881
					case self::XLS_Type_TOPMARGIN:				$this->_readTopMargin();				break;
882
					case self::XLS_Type_BOTTOMMARGIN:			$this->_readBottomMargin();				break;
883
					case self::XLS_Type_PAGESETUP:				$this->_readPageSetup();				break;
884
					case self::XLS_Type_PROTECT:				$this->_readProtect();					break;
885
					case self::XLS_Type_SCENPROTECT:			$this->_readScenProtect();				break;
886
					case self::XLS_Type_OBJECTPROTECT:			$this->_readObjectProtect();			break;
887
					case self::XLS_Type_PASSWORD:				$this->_readPassword();					break;
888
					case self::XLS_Type_DEFCOLWIDTH:			$this->_readDefColWidth();				break;
889
					case self::XLS_Type_COLINFO:				$this->_readColInfo();					break;
890
					case self::XLS_Type_DIMENSION:				$this->_readDefault();					break;
891
					case self::XLS_Type_ROW:					$this->_readRow();						break;
892
					case self::XLS_Type_DBCELL:					$this->_readDefault();					break;
893
					case self::XLS_Type_RK:						$this->_readRk();						break;
894
					case self::XLS_Type_LABELSST:				$this->_readLabelSst();					break;
895
					case self::XLS_Type_MULRK:					$this->_readMulRk();					break;
896
					case self::XLS_Type_NUMBER:					$this->_readNumber();					break;
897
					case self::XLS_Type_FORMULA:				$this->_readFormula();					break;
898
					case self::XLS_Type_SHAREDFMLA:				$this->_readSharedFmla();				break;
899
					case self::XLS_Type_BOOLERR:				$this->_readBoolErr();					break;
900
					case self::XLS_Type_MULBLANK:				$this->_readMulBlank();					break;
901
					case self::XLS_Type_LABEL:					$this->_readLabel();					break;
902
					case self::XLS_Type_BLANK:					$this->_readBlank();					break;
903
					case self::XLS_Type_MSODRAWING:				$this->_readMsoDrawing();				break;
904
					case self::XLS_Type_OBJ:					$this->_readObj();						break;
905
					case self::XLS_Type_WINDOW2:				$this->_readWindow2();					break;
906
					case self::XLS_Type_SCL:					$this->_readScl();						break;
907
					case self::XLS_Type_PANE:					$this->_readPane();						break;
908
					case self::XLS_Type_SELECTION:				$this->_readSelection();				break;
909
					case self::XLS_Type_MERGEDCELLS:			$this->_readMergedCells();				break;
910
					case self::XLS_Type_HYPERLINK:				$this->_readHyperLink();				break;
911
					case self::XLS_Type_DATAVALIDATIONS:		$this->_readDataValidations();			break;
912
					case self::XLS_Type_DATAVALIDATION:			$this->_readDataValidation();			break;
913
					case self::XLS_Type_SHEETLAYOUT:			$this->_readSheetLayout();				break;
914
					case self::XLS_Type_SHEETPROTECTION:		$this->_readSheetProtection();			break;
915
					case self::XLS_Type_RANGEPROTECTION:		$this->_readRangeProtection();			break;
916
					case self::XLS_Type_NOTE:					$this->_readNote();						break;
917
					//case self::XLS_Type_IMDATA:				$this->_readImData();					break;
918
					case self::XLS_Type_TXO:					$this->_readTextObject();				break;
919
					case self::XLS_Type_CONTINUE:				$this->_readContinue();					break;
920
					case self::XLS_Type_EOF:					$this->_readDefault();					break 2;
921
					default:									$this->_readDefault();					break;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
922
				}
923
924
			}
925
926
			// treat MSODRAWING records, sheet-level Escher
927
			if (!$this->_readDataOnly && $this->_drawingData) {
928
				$escherWorksheet = new PHPExcel_Shared_Escher();
929
				$reader = new PHPExcel_Reader_Excel5_Escher($escherWorksheet);
930
				$escherWorksheet = $reader->load($this->_drawingData);
931
932
				// debug Escher stream
933
				//$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
934
				//$debug->load($this->_drawingData);
935
936
				// get all spContainers in one long array, so they can be mapped to OBJ records
937
				$allSpContainers = $escherWorksheet->getDgContainer()->getSpgrContainer()->getAllSpContainers();
938
			}
939
940
			// treat OBJ records
941
			foreach ($this->_objs as $n => $obj) {
942
//				echo '<hr /><b>Object</b> reference is ',$n,'<br />';
943
//				var_dump($obj);
944
//				echo '<br />';
945
946
				// the first shape container never has a corresponding OBJ record, hence $n + 1
947
				$spContainer = $allSpContainers[$n + 1];
0 ignored issues
show
Bug introduced by
The variable $allSpContainers does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
948
949
				// we skip all spContainers that are a part of a group shape since we cannot yet handle those
950
				if ($spContainer->getNestingLevel() > 1) {
951
					continue;
952
				}
953
954
				// calculate the width and height of the shape
955
				list($startColumn, $startRow) = PHPExcel_Cell::coordinateFromString($spContainer->getStartCoordinates());
956
				list($endColumn, $endRow) = PHPExcel_Cell::coordinateFromString($spContainer->getEndCoordinates());
957
958
				$startOffsetX = $spContainer->getStartOffsetX();
959
				$startOffsetY = $spContainer->getStartOffsetY();
960
				$endOffsetX = $spContainer->getEndOffsetX();
961
				$endOffsetY = $spContainer->getEndOffsetY();
962
963
				$width = PHPExcel_Shared_Excel5::getDistanceX($this->_phpSheet, $startColumn, $startOffsetX, $endColumn, $endOffsetX);
964
				$height = PHPExcel_Shared_Excel5::getDistanceY($this->_phpSheet, $startRow, $startOffsetY, $endRow, $endOffsetY);
965
966
				// calculate offsetX and offsetY of the shape
967
				$offsetX = $startOffsetX * PHPExcel_Shared_Excel5::sizeCol($this->_phpSheet, $startColumn) / 1024;
968
				$offsetY = $startOffsetY * PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet, $startRow) / 256;
969
970
				switch ($obj['otObjType']) {
971
972
				case 0x19:
973
					// Note
974
//					echo 'Cell Annotation Object<br />';
975
//					echo 'Object ID is ',$obj['idObjID'],'<br />';
976
//
977
					if (isset($this->_cellNotes[$obj['idObjID']])) {
978
						$cellNote = $this->_cellNotes[$obj['idObjID']];
979
980
//						echo '_cellNotes[',$obj['idObjID'],']: ';
981
//						var_dump($cellNote);
982
//						echo '<br />';
983
//
984
						if (isset($this->_textObjects[$obj['idObjID']])) {
985
							$textObject = $this->_textObjects[$obj['idObjID']];
986
//							echo '_textObject: ';
987
//							var_dump($textObject);
988
//							echo '<br />';
989
//
990
							$this->_cellNotes[$obj['idObjID']]['objTextData'] = $textObject;
991
							$text = $textObject['text'];
992
						}
993
//						echo $text,'<br />';
994
					}
995
					break;
996
997
				case 0x08:
998
//					echo 'Picture Object<br />';
999
					// picture
1000
1001
					// get index to BSE entry (1-based)
1002
					$BSEindex = $spContainer->getOPT(0x0104);
1003
					$BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection();
0 ignored issues
show
Bug introduced by
The variable $escherWorkbook does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1004
					$BSE = $BSECollection[$BSEindex - 1];
1005
					$blipType = $BSE->getBlipType();
1006
1007
					// need check because some blip types are not supported by Escher reader such as EMF
1008
					if ($blip = $BSE->getBlip()) {
1009
						$ih = imagecreatefromstring($blip->getData());
1010
						$drawing = new PHPExcel_Worksheet_MemoryDrawing();
1011
						$drawing->setImageResource($ih);
1012
1013
						// width, height, offsetX, offsetY
1014
						$drawing->setResizeProportional(false);
1015
						$drawing->setWidth($width);
1016
						$drawing->setHeight($height);
1017
						$drawing->setOffsetX($offsetX);
1018
						$drawing->setOffsetY($offsetY);
1019
1020
						switch ($blipType) {
1021
							case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG:
1022
								$drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_JPEG);
1023
								$drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG);
1024
								break;
1025
1026
							case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG:
1027
								$drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG);
1028
								$drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG);
1029
								break;
1030
						}
1031
1032
						$drawing->setWorksheet($this->_phpSheet);
1033
						$drawing->setCoordinates($spContainer->getStartCoordinates());
1034
					}
1035
1036
					break;
1037
1038
				default:
1039
					// other object type
1040
					break;
1041
1042
				}
1043
			}
1044
1045
			// treat SHAREDFMLA records
1046
			if ($this->_version == self::XLS_BIFF8) {
1047
				foreach ($this->_sharedFormulaParts as $cell => $baseCell) {
1048
					list($column, $row) = PHPExcel_Cell::coordinateFromString($cell);
1049
					if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle()) ) {
1050
						$formula = $this->_getFormulaFromStructure($this->_sharedFormulas[$baseCell], $cell);
1051
						$this->_phpSheet->getCell($cell)->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
1052
					}
1053
				}
1054
			}
1055
1056
			if (!empty($this->_cellNotes)) {
1057
				foreach($this->_cellNotes as $note => $noteDetails) {
1058
//					echo '<b>Cell annotation ',$note,'</b><br />';
1059
//					var_dump($noteDetails);
1060
//					echo '<br />';
1061
					$cellAddress = str_replace('$','',$noteDetails['cellRef']);
1062
					$this->_phpSheet->getComment( $cellAddress )
1063
													->setAuthor( $noteDetails['author'] )
1064
													->setText($this->_parseRichText($noteDetails['objTextData']['text']) );
1065
				}
1066
			}
1067
		}
1068
1069
		// add the named ranges (defined names)
1070
		foreach ($this->_definedname as $definedName) {
1071
			if ($definedName['isBuiltInName']) {
1072
				switch ($definedName['name']) {
1073
1074
				case pack('C', 0x06):
1075
					// print area
1076
					//	in general, formula looks like this: Foo!$C$7:$J$66,Bar!$A$1:$IV$2
1077
1078
					$ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
1079
1080
					$extractedRanges = array();
1081
					foreach ($ranges as $range) {
1082
						// $range should look like one of these
1083
						//		Foo!$C$7:$J$66
1084
						//		Bar!$A$1:$IV$2
1085
1086
						$explodes = explode('!', $range);	// FIXME: what if sheetname contains exclamation mark?
1087
						$sheetName = $explodes[0];
1088
1089
						if (count($explodes) == 2) {
1090
							$extractedRanges[] = str_replace('$', '', $explodes[1]); // C7:J66
1091
						}
1092
					}
1093
					if ($docSheet = $this->_phpExcel->getSheetByName($sheetName)) {
0 ignored issues
show
Bug introduced by
The variable $sheetName does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1094
						$docSheet->getPageSetup()->setPrintArea(implode(',', $extractedRanges)); // C7:J66,A1:IV2
1095
					}
1096
					break;
1097
1098
				case pack('C', 0x07):
1099
					// print titles (repeating rows)
1100
					// Assuming BIFF8, there are 3 cases
1101
					// 1. repeating rows
1102
					//		formula looks like this: Sheet!$A$1:$IV$2
1103
					//		rows 1-2 repeat
1104
					// 2. repeating columns
1105
					//		formula looks like this: Sheet!$A$1:$B$65536
1106
					//		columns A-B repeat
1107
					// 3. both repeating rows and repeating columns
1108
					//		formula looks like this: Sheet!$A$1:$B$65536,Sheet!$A$1:$IV$2
1109
1110
					$ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
1111
1112
					foreach ($ranges as $range) {
1113
						// $range should look like this one of these
1114
						//		Sheet!$A$1:$B$65536
1115
						//		Sheet!$A$1:$IV$2
1116
1117
						$explodes = explode('!', $range);
1118
1119
						if (count($explodes) == 2) {
1120
							if ($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) {
1121
1122
								$extractedRange = $explodes[1];
1123
								$extractedRange = str_replace('$', '', $extractedRange);
1124
1125
								$coordinateStrings = explode(':', $extractedRange);
1126
								if (count($coordinateStrings) == 2) {
1127
									list($firstColumn, $firstRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[0]);
1128
									list($lastColumn, $lastRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[1]);
1129
1130
									if ($firstColumn == 'A' and $lastColumn == 'IV') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1131
										// then we have repeating rows
1132
										$docSheet->getPageSetup()->setRowsToRepeatAtTop(array($firstRow, $lastRow));
1133
									} elseif ($firstRow == 1 and $lastRow == 65536) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1134
										// then we have repeating columns
1135
										$docSheet->getPageSetup()->setColumnsToRepeatAtLeft(array($firstColumn, $lastColumn));
1136
									}
1137
								}
1138
							}
1139
						}
1140
					}
1141
					break;
1142
1143
				}
1144
			} else {
1145
				// Extract range
1146
				$explodes = explode('!', $definedName['formula']);
1147
1148
				if (count($explodes) == 2) {
1149
					if (($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) ||
1150
						($docSheet = $this->_phpExcel->getSheetByName(trim($explodes[0],"'")))) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $docSheet is correct as $this->_phpExcel->getShe...im($explodes[0], '\'')) (which targets PHPExcel::getSheetByName()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1151
						$extractedRange = $explodes[1];
1152
						$extractedRange = str_replace('$', '', $extractedRange);
1153
1154
						$localOnly = ($definedName['scope'] == 0) ? false : true;
1155
1156
						$scope = ($definedName['scope'] == 0) ?
1157
							null : $this->_phpExcel->getSheetByName($this->_sheets[$definedName['scope'] - 1]['name']);
1158
1159
						$this->_phpExcel->addNamedRange( new PHPExcel_NamedRange((string)$definedName['name'], $docSheet, $extractedRange, $localOnly, $scope) );
0 ignored issues
show
Bug introduced by
It seems like $docSheet can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1160
					}
1161
				} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
1162
					//	Named Value
1163
					//	TODO Provide support for named values
1164
				}
1165
			}
1166
		}
1167
1168
		return $this->_phpExcel;
1169
	}
1170
1171
1172
	/**
1173
	 * Use OLE reader to extract the relevant data streams from the OLE file
1174
	 *
1175
	 * @param string $pFilename
1176
	 */
1177
	private function _loadOLE($pFilename)
1178
	{
1179
		// OLE reader
1180
		$ole = new PHPExcel_Shared_OLERead();
1181
1182
		// get excel data,
1183
		$res = $ole->read($pFilename);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $res is correct as $ole->read($pFilename) (which targets PHPExcel_Shared_OLERead::read()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1184
		// Get workbook data: workbook stream + sheet streams
1185
		$this->_data = $ole->getStream($ole->wrkbook);
1186
1187
		// Get summary information data
1188
		$this->_summaryInformation = $ole->getStream($ole->summaryInformation);
1189
1190
		// Get additional document summary information data
1191
		$this->_documentSummaryInformation = $ole->getStream($ole->documentSummaryInformation);
1192
1193
		// Get user-defined property data
1194
//		$this->_userDefinedProperties = $ole->getUserDefinedProperties();
1195
	}
1196
1197
1198
	/**
1199
	 * Read summary information
1200
	 */
1201
	private function _readSummaryInformation()
1202
	{
1203
		if (!isset($this->_summaryInformation)) {
1204
			return;
1205
		}
1206
1207
		// offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
1208
		// offset: 2; size: 2;
1209
		// offset: 4; size: 2; OS version
1210
		// offset: 6; size: 2; OS indicator
1211
		// offset: 8; size: 16
1212
		// offset: 24; size: 4; section count
1213
		$secCount = self::_GetInt4d($this->_summaryInformation, 24);
1214
1215
		// 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
1216
		// offset: 44; size: 4
1217
		$secOffset = self::_GetInt4d($this->_summaryInformation, 44);
1218
1219
		// section header
1220
		// offset: $secOffset; size: 4; section length
1221
		$secLength = self::_GetInt4d($this->_summaryInformation, $secOffset);
1222
1223
		// offset: $secOffset+4; size: 4; property count
1224
		$countProperties = self::_GetInt4d($this->_summaryInformation, $secOffset+4);
1225
1226
		// initialize code page (used to resolve string values)
1227
		$codePage = 'CP1252';
1228
1229
		// offset: ($secOffset+8); size: var
1230
		// loop through property decarations and properties
1231
		for ($i = 0; $i < $countProperties; ++$i) {
1232
1233
			// offset: ($secOffset+8) + (8 * $i); size: 4; property ID
1234
			$id = self::_GetInt4d($this->_summaryInformation, ($secOffset+8) + (8 * $i));
1235
1236
			// Use value of property id as appropriate
1237
			// offset: ($secOffset+12) + (8 * $i); size: 4; offset from beginning of section (48)
1238
			$offset = self::_GetInt4d($this->_summaryInformation, ($secOffset+12) + (8 * $i));
1239
1240
			$type = self::_GetInt4d($this->_summaryInformation, $secOffset + $offset);
1241
1242
			// initialize property value
1243
			$value = null;
1244
1245
			// extract property value based on property type
1246
			switch ($type) {
1247
				case 0x02: // 2 byte signed integer
1248
					$value = self::_GetInt2d($this->_summaryInformation, $secOffset + 4 + $offset);
1249
					break;
1250
1251
				case 0x03: // 4 byte signed integer
1252
					$value = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
1253
					break;
1254
1255
				case 0x13: // 4 byte unsigned integer
1256
					// not needed yet, fix later if necessary
1257
					break;
1258
1259 View Code Duplication
				case 0x1E: // null-terminated string prepended by dword string length
1260
					$byteLength = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
1261
					$value = substr($this->_summaryInformation, $secOffset + 8 + $offset, $byteLength);
1262
					$value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
1263
					$value = rtrim($value);
1264
					break;
1265
1266 View Code Duplication
				case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
1267
					// PHP-time
1268
					$value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_summaryInformation, $secOffset + 4 + $offset, 8));
1269
					break;
1270
1271
				case 0x47: // Clipboard format
1272
					// not needed yet, fix later if necessary
1273
					break;
1274
			}
1275
1276
			switch ($id) {
1277
				case 0x01:	//	Code Page
1278
					$codePage = PHPExcel_Shared_CodePage::NumberToName($value);
1279
					break;
1280
1281
				case 0x02:	//	Title
1282
					$this->_phpExcel->getProperties()->setTitle($value);
1283
					break;
1284
1285
				case 0x03:	//	Subject
1286
					$this->_phpExcel->getProperties()->setSubject($value);
1287
					break;
1288
1289
				case 0x04:	//	Author (Creator)
1290
					$this->_phpExcel->getProperties()->setCreator($value);
1291
					break;
1292
1293
				case 0x05:	//	Keywords
1294
					$this->_phpExcel->getProperties()->setKeywords($value);
1295
					break;
1296
1297
				case 0x06:	//	Comments (Description)
1298
					$this->_phpExcel->getProperties()->setDescription($value);
1299
					break;
1300
1301
				case 0x07:	//	Template
1302
					//	Not supported by PHPExcel
1303
					break;
1304
1305
				case 0x08:	//	Last Saved By (LastModifiedBy)
1306
					$this->_phpExcel->getProperties()->setLastModifiedBy($value);
1307
					break;
1308
1309
				case 0x09:	//	Revision
1310
					//	Not supported by PHPExcel
1311
					break;
1312
1313
				case 0x0A:	//	Total Editing Time
1314
					//	Not supported by PHPExcel
1315
					break;
1316
1317
				case 0x0B:	//	Last Printed
1318
					//	Not supported by PHPExcel
1319
					break;
1320
1321
				case 0x0C:	//	Created Date/Time
1322
					$this->_phpExcel->getProperties()->setCreated($value);
1323
					break;
1324
1325
				case 0x0D:	//	Modified Date/Time
1326
					$this->_phpExcel->getProperties()->setModified($value);
1327
					break;
1328
1329
				case 0x0E:	//	Number of Pages
1330
					//	Not supported by PHPExcel
1331
					break;
1332
1333
				case 0x0F:	//	Number of Words
1334
					//	Not supported by PHPExcel
1335
					break;
1336
1337
				case 0x10:	//	Number of Characters
1338
					//	Not supported by PHPExcel
1339
					break;
1340
1341
				case 0x11:	//	Thumbnail
1342
					//	Not supported by PHPExcel
1343
					break;
1344
1345
				case 0x12:	//	Name of creating application
1346
					//	Not supported by PHPExcel
1347
					break;
1348
1349
				case 0x13:	//	Security
1350
					//	Not supported by PHPExcel
1351
					break;
1352
1353
			}
1354
		}
1355
	}
1356
1357
1358
	/**
1359
	 * Read additional document summary information
1360
	 */
1361
	private function _readDocumentSummaryInformation()
1362
	{
1363
		if (!isset($this->_documentSummaryInformation)) {
1364
			return;
1365
		}
1366
1367
		//	offset: 0;	size: 2;	must be 0xFE 0xFF (UTF-16 LE byte order mark)
1368
		//	offset: 2;	size: 2;
1369
		//	offset: 4;	size: 2;	OS version
1370
		//	offset: 6;	size: 2;	OS indicator
1371
		//	offset: 8;	size: 16
1372
		//	offset: 24;	size: 4;	section count
1373
		$secCount = self::_GetInt4d($this->_documentSummaryInformation, 24);
1374
//		echo '$secCount = ',$secCount,'<br />';
1375
1376
		// 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
1377
		// offset: 44;	size: 4;	first section offset
1378
		$secOffset = self::_GetInt4d($this->_documentSummaryInformation, 44);
1379
//		echo '$secOffset = ',$secOffset,'<br />';
1380
1381
		//	section header
1382
		//	offset: $secOffset;	size: 4;	section length
1383
		$secLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset);
1384
//		echo '$secLength = ',$secLength,'<br />';
1385
1386
		//	offset: $secOffset+4;	size: 4;	property count
1387
		$countProperties = self::_GetInt4d($this->_documentSummaryInformation, $secOffset+4);
1388
//		echo '$countProperties = ',$countProperties,'<br />';
1389
1390
		// initialize code page (used to resolve string values)
1391
		$codePage = 'CP1252';
1392
1393
		//	offset: ($secOffset+8);	size: var
1394
		//	loop through property decarations and properties
1395
		for ($i = 0; $i < $countProperties; ++$i) {
1396
//			echo 'Property ',$i,'<br />';
1397
			//	offset: ($secOffset+8) + (8 * $i);	size: 4;	property ID
1398
			$id = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+8) + (8 * $i));
1399
//			echo 'ID is ',$id,'<br />';
1400
1401
			// Use value of property id as appropriate
1402
			// offset: 60 + 8 * $i;	size: 4;	offset from beginning of section (48)
1403
			$offset = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+12) + (8 * $i));
1404
1405
			$type = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + $offset);
1406
//			echo 'Type is ',$type,', ';
1407
1408
			// initialize property value
1409
			$value = null;
1410
1411
			// extract property value based on property type
1412
			switch ($type) {
1413
				case 0x02:	//	2 byte signed integer
1414
					$value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1415
					break;
1416
1417
				case 0x03:	//	4 byte signed integer
1418
					$value = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1419
					break;
1420
1421
				case 0x0B:  // Boolean
1422
					$value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1423
					$value = ($value == 0 ? false : true);
1424
					break;
1425
1426
				case 0x13:	//	4 byte unsigned integer
1427
					// not needed yet, fix later if necessary
1428
					break;
1429
1430 View Code Duplication
				case 0x1E:	//	null-terminated string prepended by dword string length
1431
					$byteLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
1432
					$value = substr($this->_documentSummaryInformation, $secOffset + 8 + $offset, $byteLength);
1433
					$value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
1434
					$value = rtrim($value);
1435
					break;
1436
1437 View Code Duplication
				case 0x40:	//	Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
1438
					// PHP-Time
1439
					$value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_documentSummaryInformation, $secOffset + 4 + $offset, 8));
1440
					break;
1441
1442
				case 0x47:	//	Clipboard format
1443
					// not needed yet, fix later if necessary
1444
					break;
1445
			}
1446
1447
			switch ($id) {
1448
				case 0x01:	//	Code Page
1449
					$codePage = PHPExcel_Shared_CodePage::NumberToName($value);
1450
					break;
1451
1452
				case 0x02:	//	Category
1453
					$this->_phpExcel->getProperties()->setCategory($value);
1454
					break;
1455
1456
				case 0x03:	//	Presentation Target
1457
					//	Not supported by PHPExcel
1458
					break;
1459
1460
				case 0x04:	//	Bytes
1461
					//	Not supported by PHPExcel
1462
					break;
1463
1464
				case 0x05:	//	Lines
1465
					//	Not supported by PHPExcel
1466
					break;
1467
1468
				case 0x06:	//	Paragraphs
1469
					//	Not supported by PHPExcel
1470
					break;
1471
1472
				case 0x07:	//	Slides
1473
					//	Not supported by PHPExcel
1474
					break;
1475
1476
				case 0x08:	//	Notes
1477
					//	Not supported by PHPExcel
1478
					break;
1479
1480
				case 0x09:	//	Hidden Slides
1481
					//	Not supported by PHPExcel
1482
					break;
1483
1484
				case 0x0A:	//	MM Clips
1485
					//	Not supported by PHPExcel
1486
					break;
1487
1488
				case 0x0B:	//	Scale Crop
1489
					//	Not supported by PHPExcel
1490
					break;
1491
1492
				case 0x0C:	//	Heading Pairs
1493
					//	Not supported by PHPExcel
1494
					break;
1495
1496
				case 0x0D:	//	Titles of Parts
1497
					//	Not supported by PHPExcel
1498
					break;
1499
1500
				case 0x0E:	//	Manager
1501
					$this->_phpExcel->getProperties()->setManager($value);
1502
					break;
1503
1504
				case 0x0F:	//	Company
1505
					$this->_phpExcel->getProperties()->setCompany($value);
1506
					break;
1507
1508
				case 0x10:	//	Links up-to-date
1509
					//	Not supported by PHPExcel
1510
					break;
1511
1512
			}
1513
		}
1514
	}
1515
1516
1517
	/**
1518
	 * Reads a general type of BIFF record. Does nothing except for moving stream pointer forward to next record.
1519
	 */
1520 View Code Duplication
	private function _readDefault()
1521
	{
1522
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
1523
//		$recordData = substr($this->_data, $this->_pos + 4, $length);
1524
1525
		// move stream pointer to next record
1526
		$this->_pos += 4 + $length;
1527
	}
1528
1529
1530
	/**
1531
	 *	The NOTE record specifies a comment associated with a particular cell. In Excel 95 (BIFF7) and earlier versions,
1532
	 *		this record stores a note (cell note). This feature was significantly enhanced in Excel 97.
1533
	 */
1534
	private function _readNote()
1535
	{
1536
//		echo '<b>Read Cell Annotation</b><br />';
1537
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
1538
		$recordData = substr($this->_data, $this->_pos + 4, $length);
1539
1540
		// move stream pointer to next record
1541
		$this->_pos += 4 + $length;
1542
1543
		if ($this->_readDataOnly) {
1544
			return;
1545
		}
1546
1547
		$cellAddress = $this->_readBIFF8CellAddress(substr($recordData, 0, 4));
1548
		if ($this->_version == self::XLS_BIFF8) {
1549
			$noteObjID = self::_GetInt2d($recordData, 6);
1550
			$noteAuthor = self::_readUnicodeStringLong(substr($recordData, 8));
1551
			$noteAuthor = $noteAuthor['value'];
1552
//			echo 'Note Address=',$cellAddress,'<br />';
1553
//			echo 'Note Object ID=',$noteObjID,'<br />';
1554
//			echo 'Note Author=',$noteAuthor,'<hr />';
1555
//
1556
			$this->_cellNotes[$noteObjID] = array('cellRef'		=> $cellAddress,
1557
												  'objectID'	=> $noteObjID,
1558
												  'author'		=> $noteAuthor
1559
												 );
1560
		} else {
1561
			$extension = false;
1562
			if ($cellAddress == '$B$65536') {
1563
				//	If the address row is -1 and the column is 0, (which translates as $B$65536) then this is a continuation
1564
				//		note from the previous cell annotation. We're not yet handling this, so annotations longer than the
1565
				//		max 2048 bytes will probably throw a wobbly.
1566
				$row = self::_GetInt2d($recordData, 0);
1567
				$extension = true;
1568
				$cellAddress = array_pop(array_keys($this->_phpSheet->getComments()));
0 ignored issues
show
Bug introduced by
array_keys($this->_phpSheet->getComments()) cannot be passed to array_pop() as the parameter $array expects a reference.
Loading history...
1569
			}
1570
//			echo 'Note Address=',$cellAddress,'<br />';
1571
1572
			$cellAddress = str_replace('$','',$cellAddress);
1573
			$noteLength = self::_GetInt2d($recordData, 4);
1574
			$noteText = trim(substr($recordData, 6));
1575
//			echo 'Note Length=',$noteLength,'<br />';
1576
//			echo 'Note Text=',$noteText,'<br />';
1577
1578
			if ($extension) {
1579
				//	Concatenate this extension with the currently set comment for the cell
1580
				$comment = $this->_phpSheet->getComment( $cellAddress );
1581
				$commentText = $comment->getText()->getPlainText();
1582
				$comment->setText($this->_parseRichText($commentText.$noteText) );
1583
			} else {
1584
				//	Set comment for the cell
1585
				$this->_phpSheet->getComment( $cellAddress )
1586
//													->setAuthor( $author )
1587
													->setText($this->_parseRichText($noteText) );
1588
			}
1589
		}
1590
1591
	}
1592
1593
1594
	/**
1595
	 *	The TEXT Object record contains the text associated with a cell annotation.
1596
	 */
1597
	private function _readTextObject()
1598
	{
1599
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
1600
		$recordData = substr($this->_data, $this->_pos + 4, $length);
1601
1602
		// move stream pointer to next record
1603
		$this->_pos += 4 + $length;
1604
1605
		if ($this->_readDataOnly) {
1606
			return;
1607
		}
1608
1609
		// recordData consists of an array of subrecords looking like this:
1610
		//	grbit: 2 bytes; Option Flags
1611
		//	rot: 2 bytes; rotation
1612
		//	cchText: 2 bytes; length of the text (in the first continue record)
1613
		//	cbRuns: 2 bytes; length of the formatting (in the second continue record)
1614
		// followed by the continuation records containing the actual text and formatting
1615
		$grbitOpts	= self::_GetInt2d($recordData, 0);
1616
		$rot		= self::_GetInt2d($recordData, 2);
1617
		$cchText	= self::_GetInt2d($recordData, 10);
1618
		$cbRuns		= self::_GetInt2d($recordData, 12);
1619
		$text		= $this->_getSplicedRecordData();
1620
1621
		$this->_textObjects[$this->textObjRef] = array(
1622
				'text'		=> substr($text["recordData"],$text["spliceOffsets"][0]+1,$cchText),
1623
				'format'	=> substr($text["recordData"],$text["spliceOffsets"][1],$cbRuns),
1624
				'alignment'	=> $grbitOpts,
1625
				'rotation'	=> $rot
1626
			 );
1627
1628
//		echo '<b>_readTextObject()</b><br />';
1629
//		var_dump($this->_textObjects[$this->textObjRef]);
1630
//		echo '<br />';
1631
	}
1632
1633
1634
	/**
1635
	 * Read BOF
1636
	 */
1637
	private function _readBof()
1638
	{
1639
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
1640
		$recordData = substr($this->_data, $this->_pos + 4, $length);
1641
1642
		// move stream pointer to next record
1643
		$this->_pos += 4 + $length;
1644
1645
		// offset: 2; size: 2; type of the following data
1646
		$substreamType = self::_GetInt2d($recordData, 2);
1647
1648
		switch ($substreamType) {
1649
			case self::XLS_WorkbookGlobals:
1650
				$version = self::_GetInt2d($recordData, 0);
1651
				if (($version != self::XLS_BIFF8) && ($version != self::XLS_BIFF7)) {
1652
					throw new Exception('Cannot read this Excel file. Version is too old.');
1653
				}
1654
				$this->_version = $version;
1655
				break;
1656
1657
			case self::XLS_Worksheet:
1658
				// do not use this version information for anything
1659
				// it is unreliable (OpenOffice doc, 5.8), use only version information from the global stream
1660
				break;
1661
1662
			default:
1663
				// substream, e.g. chart
1664
				// just skip the entire substream
1665
				do {
1666
					$code = self::_GetInt2d($this->_data, $this->_pos);
1667
					$this->_readDefault();
1668
				} while ($code != self::XLS_Type_EOF && $this->_pos < $this->_dataSize);
1669
				break;
1670
		}
1671
	}
1672
1673
1674
	/**
1675
	 * FILEPASS
1676
	 *
1677
	 * This record is part of the File Protection Block. It
1678
	 * contains information about the read/write password of the
1679
	 * file. All record contents following this record will be
1680
	 * encrypted.
1681
	 *
1682
	 * --	"OpenOffice.org's Documentation of the Microsoft
1683
	 * 		Excel File Format"
1684
	 */
1685 View Code Duplication
	private function _readFilepass()
1686
	{
1687
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
1688
//		$recordData = substr($this->_data, $this->_pos + 4, $length);
1689
1690
		// move stream pointer to next record
1691
		$this->_pos += 4 + $length;
1692
1693
		throw new Exception('Cannot read encrypted file');
1694
	}
1695
1696
1697
	/**
1698
	 * CODEPAGE
1699
	 *
1700
	 * This record stores the text encoding used to write byte
1701
	 * strings, stored as MS Windows code page identifier.
1702
	 *
1703
	 * --	"OpenOffice.org's Documentation of the Microsoft
1704
	 * 		Excel File Format"
1705
	 */
1706
	private function _readCodepage()
1707
	{
1708
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
1709
		$recordData = substr($this->_data, $this->_pos + 4, $length);
1710
1711
		// move stream pointer to next record
1712
		$this->_pos += 4 + $length;
1713
1714
		// offset: 0; size: 2; code page identifier
1715
		$codepage = self::_GetInt2d($recordData, 0);
1716
1717
		$this->_codepage = PHPExcel_Shared_CodePage::NumberToName($codepage);
1718
	}
1719
1720
1721
	/**
1722
	 * DATEMODE
1723
	 *
1724
	 * This record specifies the base date for displaying date
1725
	 * values. All dates are stored as count of days past this
1726
	 * base date. In BIFF2-BIFF4 this record is part of the
1727
	 * Calculation Settings Block. In BIFF5-BIFF8 it is
1728
	 * stored in the Workbook Globals Substream.
1729
	 *
1730
	 * --	"OpenOffice.org's Documentation of the Microsoft
1731
	 * 		Excel File Format"
1732
	 */
1733
	private function _readDateMode()
1734
	{
1735
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
1736
		$recordData = substr($this->_data, $this->_pos + 4, $length);
1737
1738
		// move stream pointer to next record
1739
		$this->_pos += 4 + $length;
1740
1741
		// offset: 0; size: 2; 0 = base 1900, 1 = base 1904
1742
		PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900);
1743
		if (ord($recordData{0}) == 1) {
1744
			PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_MAC_1904);
1745
		}
1746
	}
1747
1748
1749
	/**
1750
	 * Read a FONT record
1751
	 */
1752
	private function _readFont()
1753
	{
1754
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
1755
		$recordData = substr($this->_data, $this->_pos + 4, $length);
1756
1757
		// move stream pointer to next record
1758
		$this->_pos += 4 + $length;
1759
1760
		if (!$this->_readDataOnly) {
1761
			$objFont = new PHPExcel_Style_Font();
1762
1763
			// offset: 0; size: 2; height of the font (in twips = 1/20 of a point)
1764
			$size = self::_GetInt2d($recordData, 0);
1765
			$objFont->setSize($size / 20);
1766
1767
			// offset: 2; size: 2; option flags
1768
				// bit: 0; mask 0x0001; bold (redundant in BIFF5-BIFF8)
1769
				// bit: 1; mask 0x0002; italic
1770
				$isItalic = (0x0002 & self::_GetInt2d($recordData, 2)) >> 1;
1771
				if ($isItalic) $objFont->setItalic(true);
1772
1773
				// bit: 2; mask 0x0004; underlined (redundant in BIFF5-BIFF8)
1774
				// bit: 3; mask 0x0008; strike
1775
				$isStrike = (0x0008 & self::_GetInt2d($recordData, 2)) >> 3;
1776
				if ($isStrike) $objFont->setStrikethrough(true);
1777
1778
			// offset: 4; size: 2; colour index
1779
			$colorIndex = self::_GetInt2d($recordData, 4);
1780
			$objFont->colorIndex = $colorIndex;
0 ignored issues
show
Bug introduced by
The property colorIndex does not seem to exist in PHPExcel_Style_Font.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1781
1782
			// offset: 6; size: 2; font weight
1783
			$weight = self::_GetInt2d($recordData, 6);
1784
			switch ($weight) {
1785
				case 0x02BC:
1786
					$objFont->setBold(true);
1787
					break;
1788
			}
1789
1790
			// offset: 8; size: 2; escapement type
1791
			$escapement = self::_GetInt2d($recordData, 8);
1792
			switch ($escapement) {
1793
				case 0x0001:
1794
					$objFont->setSuperScript(true);
1795
					break;
1796
				case 0x0002:
1797
					$objFont->setSubScript(true);
1798
					break;
1799
			}
1800
1801
			// offset: 10; size: 1; underline type
1802
			$underlineType = ord($recordData{10});
1803
			switch ($underlineType) {
1804
				case 0x00:
1805
					break; // no underline
1806
				case 0x01:
1807
					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
1808
					break;
1809
				case 0x02:
1810
					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLE);
1811
					break;
1812
				case 0x21:
1813
					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING);
1814
					break;
1815
				case 0x22:
1816
					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING);
1817
					break;
1818
			}
1819
1820
			// offset: 11; size: 1; font family
1821
			// offset: 12; size: 1; character set
1822
			// offset: 13; size: 1; not used
1823
			// offset: 14; size: var; font name
1824 View Code Duplication
			if ($this->_version == self::XLS_BIFF8) {
1825
				$string = self::_readUnicodeStringShort(substr($recordData, 14));
1826
			} else {
1827
				$string = $this->_readByteStringShort(substr($recordData, 14));
1828
			}
1829
			$objFont->setName($string['value']);
1830
1831
			$this->_objFonts[] = $objFont;
1832
		}
1833
	}
1834
1835
1836
	/**
1837
	 * FORMAT
1838
	 *
1839
	 * This record contains information about a number format.
1840
	 * All FORMAT records occur together in a sequential list.
1841
	 *
1842
	 * In BIFF2-BIFF4 other records referencing a FORMAT record
1843
	 * contain a zero-based index into this list. From BIFF5 on
1844
	 * the FORMAT record contains the index itself that will be
1845
	 * used by other records.
1846
	 *
1847
	 * --	"OpenOffice.org's Documentation of the Microsoft
1848
	 * 		Excel File Format"
1849
	 */
1850
	private function _readFormat()
1851
	{
1852
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
1853
		$recordData = substr($this->_data, $this->_pos + 4, $length);
1854
1855
		// move stream pointer to next record
1856
		$this->_pos += 4 + $length;
1857
1858
		if (!$this->_readDataOnly) {
1859
			$indexCode = self::_GetInt2d($recordData, 0);
1860
1861 View Code Duplication
			if ($this->_version == self::XLS_BIFF8) {
1862
				$string = self::_readUnicodeStringLong(substr($recordData, 2));
1863
			} else {
1864
				// BIFF7
1865
				$string = $this->_readByteStringShort(substr($recordData, 2));
1866
			}
1867
1868
			$formatString = $string['value'];
1869
			$this->_formats[$indexCode] = $formatString;
1870
		}
1871
	}
1872
1873
1874
	/**
1875
	 * XF - Extended Format
1876
	 *
1877
	 * This record contains formatting information for cells, rows, columns or styles.
1878
	 * According to http://support.microsoft.com/kb/147732 there are always at least 15 cell style XF
1879
	 * and 1 cell XF.
1880
	 * Inspection of Excel files generated by MS Office Excel shows that XF records 0-14 are cell style XF
1881
	 * and XF record 15 is a cell XF
1882
	 * We only read the first cell style XF and skip the remaining cell style XF records
1883
	 * We read all cell XF records.
1884
	 *
1885
	 * --	"OpenOffice.org's Documentation of the Microsoft
1886
	 * 		Excel File Format"
1887
	 */
1888
	private function _readXf()
1889
	{
1890
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
1891
		$recordData = substr($this->_data, $this->_pos + 4, $length);
1892
1893
		// move stream pointer to next record
1894
		$this->_pos += 4 + $length;
1895
1896
		$objStyle = new PHPExcel_Style();
1897
1898
		if (!$this->_readDataOnly) {
1899
			// offset:  0; size: 2; Index to FONT record
1900
			if (self::_GetInt2d($recordData, 0) < 4) {
1901
				$fontIndex = self::_GetInt2d($recordData, 0);
1902
			} else {
1903
				// this has to do with that index 4 is omitted in all BIFF versions for some strange reason
1904
				// check the OpenOffice documentation of the FONT record
1905
				$fontIndex = self::_GetInt2d($recordData, 0) - 1;
1906
			}
1907
			$objStyle->setFont($this->_objFonts[$fontIndex]);
1908
1909
			// offset:  2; size: 2; Index to FORMAT record
1910
			$numberFormatIndex = self::_GetInt2d($recordData, 2);
1911
			if (isset($this->_formats[$numberFormatIndex])) {
1912
				// then we have user-defined format code
1913
				$numberformat = array('code' => $this->_formats[$numberFormatIndex]);
1914
			} elseif (($code = PHPExcel_Style_NumberFormat::builtInFormatCode($numberFormatIndex)) !== '') {
1915
				// then we have built-in format code
1916
				$numberformat = array('code' => $code);
1917
			} else {
1918
				// we set the general format code
1919
				$numberformat = array('code' => 'General');
1920
			}
1921
			$objStyle->getNumberFormat()->setFormatCode($numberformat['code']);
1922
1923
			// offset:  4; size: 2; XF type, cell protection, and parent style XF
1924
			// bit 2-0; mask 0x0007; XF_TYPE_PROT
1925
			$xfTypeProt = self::_GetInt2d($recordData, 4);
1926
			// bit 0; mask 0x01; 1 = cell is locked
1927
			$isLocked = (0x01 & $xfTypeProt) >> 0;
1928
			$objStyle->getProtection()->setLocked($isLocked ?
1929
				PHPExcel_Style_Protection::PROTECTION_INHERIT : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
1930
1931
			// bit 1; mask 0x02; 1 = Formula is hidden
1932
			$isHidden = (0x02 & $xfTypeProt) >> 1;
1933
			$objStyle->getProtection()->setHidden($isHidden ?
1934
				PHPExcel_Style_Protection::PROTECTION_PROTECTED : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
1935
1936
			// bit 2; mask 0x04; 0 = Cell XF, 1 = Cell Style XF
1937
			$isCellStyleXf = (0x04 & $xfTypeProt) >> 2;
1938
1939
			// offset:  6; size: 1; Alignment and text break
1940
			// bit 2-0, mask 0x07; horizontal alignment
1941
			$horAlign = (0x07 & ord($recordData{6})) >> 0;
1942
			switch ($horAlign) {
1943
				case 0:
1944
					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_GENERAL);
1945
					break;
1946
				case 1:
1947
					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
1948
					break;
1949
				case 2:
1950
					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
1951
					break;
1952
				case 3:
1953
					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
1954
					break;
1955
				case 5:
1956
					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY);
1957
					break;
1958
				case 6:
1959
					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS);
1960
					break;
1961
			}
1962
			// bit 3, mask 0x08; wrap text
1963
			$wrapText = (0x08 & ord($recordData{6})) >> 3;
1964
			switch ($wrapText) {
1965
				case 0:
1966
					$objStyle->getAlignment()->setWrapText(false);
1967
					break;
1968
				case 1:
1969
					$objStyle->getAlignment()->setWrapText(true);
1970
					break;
1971
			}
1972
			// bit 6-4, mask 0x70; vertical alignment
1973
			$vertAlign = (0x70 & ord($recordData{6})) >> 4;
1974
			switch ($vertAlign) {
1975
				case 0:
1976
					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_TOP);
1977
					break;
1978
				case 1:
1979
					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
1980
					break;
1981
				case 2:
1982
					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_BOTTOM);
1983
					break;
1984
				case 3:
1985
					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_JUSTIFY);
1986
					break;
1987
			}
1988
1989
			if ($this->_version == self::XLS_BIFF8) {
1990
				// offset:  7; size: 1; XF_ROTATION: Text rotation angle
1991
					$angle = ord($recordData{7});
1992
					$rotation = 0;
1993
					if ($angle <= 90) {
1994
						$rotation = $angle;
1995
					} else if ($angle <= 180) {
1996
						$rotation = 90 - $angle;
1997
					} else if ($angle == 255) {
1998
						$rotation = -165;
1999
					}
2000
					$objStyle->getAlignment()->setTextRotation($rotation);
2001
2002
				// offset:  8; size: 1; Indentation, shrink to cell size, and text direction
2003
					// bit: 3-0; mask: 0x0F; indent level
2004
					$indent = (0x0F & ord($recordData{8})) >> 0;
2005
					$objStyle->getAlignment()->setIndent($indent);
2006
2007
					// bit: 4; mask: 0x10; 1 = shrink content to fit into cell
2008
					$shrinkToFit = (0x10 & ord($recordData{8})) >> 4;
2009
					switch ($shrinkToFit) {
2010
						case 0:
2011
							$objStyle->getAlignment()->setShrinkToFit(false);
2012
							break;
2013
						case 1:
2014
							$objStyle->getAlignment()->setShrinkToFit(true);
2015
							break;
2016
					}
2017
2018
				// offset:  9; size: 1; Flags used for attribute groups
2019
2020
				// offset: 10; size: 4; Cell border lines and background area
2021
					// bit: 3-0; mask: 0x0000000F; left style
2022 View Code Duplication
					if ($bordersLeftStyle = self::_mapBorderStyle((0x0000000F & self::_GetInt4d($recordData, 10)) >> 0)) {
2023
						$objStyle->getBorders()->getLeft()->setBorderStyle($bordersLeftStyle);
2024
					}
2025
					// bit: 7-4; mask: 0x000000F0; right style
2026 View Code Duplication
					if ($bordersRightStyle = self::_mapBorderStyle((0x000000F0 & self::_GetInt4d($recordData, 10)) >> 4)) {
2027
						$objStyle->getBorders()->getRight()->setBorderStyle($bordersRightStyle);
2028
					}
2029
					// bit: 11-8; mask: 0x00000F00; top style
2030 View Code Duplication
					if ($bordersTopStyle = self::_mapBorderStyle((0x00000F00 & self::_GetInt4d($recordData, 10)) >> 8)) {
2031
						$objStyle->getBorders()->getTop()->setBorderStyle($bordersTopStyle);
2032
					}
2033
					// bit: 15-12; mask: 0x0000F000; bottom style
2034 View Code Duplication
					if ($bordersBottomStyle = self::_mapBorderStyle((0x0000F000 & self::_GetInt4d($recordData, 10)) >> 12)) {
2035
						$objStyle->getBorders()->getBottom()->setBorderStyle($bordersBottomStyle);
2036
					}
2037
					// bit: 22-16; mask: 0x007F0000; left color
2038
					$objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & self::_GetInt4d($recordData, 10)) >> 16;
0 ignored issues
show
Bug introduced by
The property colorIndex does not seem to exist in PHPExcel_Style_Border.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
2039
2040
					// bit: 29-23; mask: 0x3F800000; right color
2041
					$objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & self::_GetInt4d($recordData, 10)) >> 23;
2042
2043
					// bit: 30; mask: 0x40000000; 1 = diagonal line from top left to right bottom
2044
					$diagonalDown = (0x40000000 & self::_GetInt4d($recordData, 10)) >> 30 ?
2045
						true : false;
2046
2047
					// bit: 31; mask: 0x80000000; 1 = diagonal line from bottom left to top right
2048
					$diagonalUp = (0x80000000 & self::_GetInt4d($recordData, 10)) >> 31 ?
2049
						true : false;
2050
2051 View Code Duplication
					if ($diagonalUp == false && $diagonalDown == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2052
						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_NONE);
2053
					} elseif ($diagonalUp == true && $diagonalDown == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2054
						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_UP);
2055
					} elseif ($diagonalUp == false && $diagonalDown == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2056
						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_DOWN);
2057
					} elseif ($diagonalUp == true && $diagonalDown == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2058
						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_BOTH);
2059
					}
2060
2061
				// offset: 14; size: 4;
2062
					// bit: 6-0; mask: 0x0000007F; top color
2063
					$objStyle->getBorders()->getTop()->colorIndex = (0x0000007F & self::_GetInt4d($recordData, 14)) >> 0;
2064
2065
					// bit: 13-7; mask: 0x00003F80; bottom color
2066
					$objStyle->getBorders()->getBottom()->colorIndex = (0x00003F80 & self::_GetInt4d($recordData, 14)) >> 7;
2067
2068
					// bit: 20-14; mask: 0x001FC000; diagonal color
2069
					$objStyle->getBorders()->getDiagonal()->colorIndex = (0x001FC000 & self::_GetInt4d($recordData, 14)) >> 14;
2070
2071
					// bit: 24-21; mask: 0x01E00000; diagonal style
2072 View Code Duplication
					if ($bordersDiagonalStyle = self::_mapBorderStyle((0x01E00000 & self::_GetInt4d($recordData, 14)) >> 21)) {
2073
						$objStyle->getBorders()->getDiagonal()->setBorderStyle($bordersDiagonalStyle);
2074
					}
2075
2076
					// bit: 31-26; mask: 0xFC000000 fill pattern
2077
					if ($fillType = self::_mapFillPattern((0xFC000000 & self::_GetInt4d($recordData, 14)) >> 26)) {
2078
						$objStyle->getFill()->setFillType($fillType);
2079
					}
2080
				// offset: 18; size: 2; pattern and background colour
2081
					// bit: 6-0; mask: 0x007F; color index for pattern color
2082
					$objStyle->getFill()->startcolorIndex = (0x007F & self::_GetInt2d($recordData, 18)) >> 0;
0 ignored issues
show
Bug introduced by
The property startcolorIndex does not seem to exist in PHPExcel_Style_Fill.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
2083
2084
					// bit: 13-7; mask: 0x3F80; color index for pattern background
2085
					$objStyle->getFill()->endcolorIndex = (0x3F80 & self::_GetInt2d($recordData, 18)) >> 7;
0 ignored issues
show
Bug introduced by
The property endcolorIndex does not seem to exist in PHPExcel_Style_Fill.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
2086
			} else {
2087
				// BIFF5
2088
2089
				// offset: 7; size: 1; Text orientation and flags
2090
				$orientationAndFlags = ord($recordData{7});
2091
2092
				// bit: 1-0; mask: 0x03; XF_ORIENTATION: Text orientation
2093
				$xfOrientation = (0x03 & $orientationAndFlags) >> 0;
2094
				switch ($xfOrientation) {
2095
					case 0:
2096
						$objStyle->getAlignment()->setTextRotation(0);
2097
						break;
2098
					case 1:
2099
						$objStyle->getAlignment()->setTextRotation(-165);
2100
						break;
2101
					case 2:
2102
						$objStyle->getAlignment()->setTextRotation(90);
2103
						break;
2104
					case 3:
2105
						$objStyle->getAlignment()->setTextRotation(-90);
2106
						break;
2107
				}
2108
2109
				// offset: 8; size: 4; cell border lines and background area
2110
				$borderAndBackground = self::_GetInt4d($recordData, 8);
2111
2112
				// bit: 6-0; mask: 0x0000007F; color index for pattern color
2113
				$objStyle->getFill()->startcolorIndex = (0x0000007F & $borderAndBackground) >> 0;
2114
2115
				// bit: 13-7; mask: 0x00003F80; color index for pattern background
2116
				$objStyle->getFill()->endcolorIndex = (0x00003F80 & $borderAndBackground) >> 7;
2117
2118
				// bit: 21-16; mask: 0x003F0000; fill pattern
2119
				$objStyle->getFill()->setFillType(self::_mapFillPattern((0x003F0000 & $borderAndBackground) >> 16));
2120
2121
				// bit: 24-22; mask: 0x01C00000; bottom line style
2122
				$objStyle->getBorders()->getBottom()->setBorderStyle(self::_mapBorderStyle((0x01C00000 & $borderAndBackground) >> 22));
2123
2124
				// bit: 31-25; mask: 0xFE000000; bottom line color
2125
				$objStyle->getBorders()->getBottom()->colorIndex = (0xFE000000 & $borderAndBackground) >> 25;
2126
2127
				// offset: 12; size: 4; cell border lines
2128
				$borderLines = self::_GetInt4d($recordData, 12);
2129
2130
				// bit: 2-0; mask: 0x00000007; top line style
2131
				$objStyle->getBorders()->getTop()->setBorderStyle(self::_mapBorderStyle((0x00000007 & $borderLines) >> 0));
2132
2133
				// bit: 5-3; mask: 0x00000038; left line style
2134
				$objStyle->getBorders()->getLeft()->setBorderStyle(self::_mapBorderStyle((0x00000038 & $borderLines) >> 3));
2135
2136
				// bit: 8-6; mask: 0x000001C0; right line style
2137
				$objStyle->getBorders()->getRight()->setBorderStyle(self::_mapBorderStyle((0x000001C0 & $borderLines) >> 6));
2138
2139
				// bit: 15-9; mask: 0x0000FE00; top line color index
2140
				$objStyle->getBorders()->getTop()->colorIndex = (0x0000FE00 & $borderLines) >> 9;
2141
2142
				// bit: 22-16; mask: 0x007F0000; left line color index
2143
				$objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & $borderLines) >> 16;
2144
2145
				// bit: 29-23; mask: 0x3F800000; right line color index
2146
				$objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & $borderLines) >> 23;
2147
			}
2148
2149
			// add cellStyleXf or cellXf and update mapping
2150
			if ($isCellStyleXf) {
2151
				// we only read one style XF record which is always the first
2152
				if ($this->_xfIndex == 0) {
2153
					$this->_phpExcel->addCellStyleXf($objStyle);
2154
					$this->_mapCellStyleXfIndex[$this->_xfIndex] = 0;
2155
				}
2156
			} else {
2157
				// we read all cell XF records
2158
				$this->_phpExcel->addCellXf($objStyle);
2159
				$this->_mapCellXfIndex[$this->_xfIndex] = count($this->_phpExcel->getCellXfCollection()) - 1;
2160
			}
2161
2162
			// update XF index for when we read next record
2163
			++$this->_xfIndex;
2164
		}
2165
	}
2166
2167
2168
	/**
2169
	 *
2170
	 */
2171
	private function _readXfExt()
2172
	{
2173
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2174
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2175
2176
		// move stream pointer to next record
2177
		$this->_pos += 4 + $length;
2178
2179
		if (!$this->_readDataOnly) {
2180
			// offset: 0; size: 2; 0x087D = repeated header
2181
2182
			// offset: 2; size: 2
2183
2184
			// offset: 4; size: 8; not used
2185
2186
			// offset: 12; size: 2; record version
2187
2188
			// offset: 14; size: 2; index to XF record which this record modifies
2189
			$ixfe = self::_GetInt2d($recordData, 14);
2190
2191
			// offset: 16; size: 2; not used
2192
2193
			// offset: 18; size: 2; number of extension properties that follow
2194
			$cexts = self::_GetInt2d($recordData, 18);
2195
2196
			// start reading the actual extension data
2197
			$offset = 20;
2198
			while ($offset < $length) {
2199
				// extension type
2200
				$extType = self::_GetInt2d($recordData, $offset);
2201
2202
				// extension length
2203
				$cb = self::_GetInt2d($recordData, $offset + 2);
2204
2205
				// extension data
2206
				$extData = substr($recordData, $offset + 4, $cb);
2207
2208
				switch ($extType) {
2209 View Code Duplication
					case 4:		// fill start color
2210
						$xclfType  = self::_GetInt2d($extData, 0); // color type
2211
						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2212
2213
						if ($xclfType == 2) {
2214
							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2215
2216
							// modify the relevant style property
2217
							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2218
								$fill = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFill();
2219
								$fill->getStartColor()->setRGB($rgb);
2220
								unset($fill->startcolorIndex); // normal color index does not apply, discard
2221
							}
2222
						}
2223
						break;
2224
2225 View Code Duplication
					case 5:		// fill end color
2226
						$xclfType  = self::_GetInt2d($extData, 0); // color type
2227
						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2228
2229
						if ($xclfType == 2) {
2230
							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2231
2232
							// modify the relevant style property
2233
							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2234
								$fill = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFill();
2235
								$fill->getEndColor()->setRGB($rgb);
2236
								unset($fill->endcolorIndex); // normal color index does not apply, discard
2237
							}
2238
						}
2239
						break;
2240
2241 View Code Duplication
					case 7:		// border color top
2242
						$xclfType  = self::_GetInt2d($extData, 0); // color type
2243
						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2244
2245
						if ($xclfType == 2) {
2246
							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2247
2248
							// modify the relevant style property
2249
							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2250
								$top = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getTop();
2251
								$top->getColor()->setRGB($rgb);
2252
								unset($top->colorIndex); // normal color index does not apply, discard
2253
							}
2254
						}
2255
						break;
2256
2257 View Code Duplication
					case 8:		// border color bottom
2258
						$xclfType  = self::_GetInt2d($extData, 0); // color type
2259
						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2260
2261
						if ($xclfType == 2) {
2262
							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2263
2264
							// modify the relevant style property
2265
							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2266
								$bottom = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getBottom();
2267
								$bottom->getColor()->setRGB($rgb);
2268
								unset($bottom->colorIndex); // normal color index does not apply, discard
2269
							}
2270
						}
2271
						break;
2272
2273 View Code Duplication
					case 9:		// border color left
2274
						$xclfType  = self::_GetInt2d($extData, 0); // color type
2275
						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2276
2277
						if ($xclfType == 2) {
2278
							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2279
2280
							// modify the relevant style property
2281
							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2282
								$left = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getLeft();
2283
								$left->getColor()->setRGB($rgb);
2284
								unset($left->colorIndex); // normal color index does not apply, discard
2285
							}
2286
						}
2287
						break;
2288
2289 View Code Duplication
					case 10:		// border color right
2290
						$xclfType  = self::_GetInt2d($extData, 0); // color type
2291
						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2292
2293
						if ($xclfType == 2) {
2294
							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2295
2296
							// modify the relevant style property
2297
							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2298
								$right = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getRight();
2299
								$right->getColor()->setRGB($rgb);
2300
								unset($right->colorIndex); // normal color index does not apply, discard
2301
							}
2302
						}
2303
						break;
2304
2305 View Code Duplication
					case 11:		// border color diagonal
2306
						$xclfType  = self::_GetInt2d($extData, 0); // color type
2307
						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2308
2309
						if ($xclfType == 2) {
2310
							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2311
2312
							// modify the relevant style property
2313
							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2314
								$diagonal = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getDiagonal();
2315
								$diagonal->getColor()->setRGB($rgb);
2316
								unset($diagonal->colorIndex); // normal color index does not apply, discard
2317
							}
2318
						}
2319
						break;
2320
2321 View Code Duplication
					case 13:	// font color
2322
						$xclfType  = self::_GetInt2d($extData, 0); // color type
2323
						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
2324
2325
						if ($xclfType == 2) {
2326
							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
2327
2328
							// modify the relevant style property
2329
							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
2330
								$font = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFont();
2331
								$font->getColor()->setRGB($rgb);
2332
								unset($font->colorIndex); // normal color index does not apply, discard
2333
							}
2334
						}
2335
						break;
2336
				}
2337
2338
				$offset += $cb;
2339
			}
2340
		}
2341
2342
	}
2343
2344
2345
	/**
2346
	 * Read STYLE record
2347
	 */
2348
	private function _readStyle()
2349
	{
2350
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2351
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2352
2353
		// move stream pointer to next record
2354
		$this->_pos += 4 + $length;
2355
2356
		if (!$this->_readDataOnly) {
2357
			// offset: 0; size: 2; index to XF record and flag for built-in style
2358
			$ixfe = self::_GetInt2d($recordData, 0);
2359
2360
			// bit: 11-0; mask 0x0FFF; index to XF record
2361
			$xfIndex = (0x0FFF & $ixfe) >> 0;
2362
2363
			// bit: 15; mask 0x8000; 0 = user-defined style, 1 = built-in style
2364
			$isBuiltIn = (bool) ((0x8000 & $ixfe) >> 15);
2365
2366
			if ($isBuiltIn) {
2367
				// offset: 2; size: 1; identifier for built-in style
2368
				$builtInId = ord($recordData{2});
2369
2370
				switch ($builtInId) {
2371
				case 0x00:
2372
					// currently, we are not using this for anything
2373
					break;
2374
2375
				default:
2376
					break;
2377
				}
2378
2379
			} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
2380
				// user-defined; not supported by PHPExcel
2381
			}
2382
		}
2383
	}
2384
2385
2386
	/**
2387
	 * Read PALETTE record
2388
	 */
2389
	private function _readPalette()
2390
	{
2391
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2392
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2393
2394
		// move stream pointer to next record
2395
		$this->_pos += 4 + $length;
2396
2397
		if (!$this->_readDataOnly) {
2398
			// offset: 0; size: 2; number of following colors
2399
			$nm = self::_GetInt2d($recordData, 0);
2400
2401
			// list of RGB colors
2402
			for ($i = 0; $i < $nm; ++$i) {
2403
				$rgb = substr($recordData, 2 + 4 * $i, 4);
2404
				$this->_palette[] = self::_readRGB($rgb);
2405
			}
2406
		}
2407
	}
2408
2409
2410
	/**
2411
	 * SHEET
2412
	 *
2413
	 * This record is  located in the  Workbook Globals
2414
	 * Substream  and represents a sheet inside the workbook.
2415
	 * One SHEET record is written for each sheet. It stores the
2416
	 * sheet name and a stream offset to the BOF record of the
2417
	 * respective Sheet Substream within the Workbook Stream.
2418
	 *
2419
	 * --	"OpenOffice.org's Documentation of the Microsoft
2420
	 * 		Excel File Format"
2421
	 */
2422
	private function _readSheet()
2423
	{
2424
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2425
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2426
2427
		// move stream pointer to next record
2428
		$this->_pos += 4 + $length;
2429
2430
		// offset: 0; size: 4; absolute stream position of the BOF record of the sheet
2431
		$rec_offset = self::_GetInt4d($recordData, 0);
2432
2433
		// offset: 4; size: 1; sheet state
2434
		switch (ord($recordData{4})) {
2435
			case 0x00: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE;    break;
2436
			case 0x01: $sheetState = PHPExcel_Worksheet::SHEETSTATE_HIDDEN;     break;
2437
			case 0x02: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VERYHIDDEN; break;
2438
			default: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE;      break;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
2439
		}
2440
2441
		// offset: 5; size: 1; sheet type
2442
		$sheetType = ord($recordData{5});
2443
2444
		// offset: 6; size: var; sheet name
2445 View Code Duplication
		if ($this->_version == self::XLS_BIFF8) {
2446
			$string = self::_readUnicodeStringShort(substr($recordData, 6));
2447
			$rec_name = $string['value'];
2448
		} elseif ($this->_version == self::XLS_BIFF7) {
2449
			$string = $this->_readByteStringShort(substr($recordData, 6));
2450
			$rec_name = $string['value'];
2451
		}
2452
2453
		$this->_sheets[] = array(
2454
			'name' => $rec_name,
0 ignored issues
show
Bug introduced by
The variable $rec_name does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2455
			'offset' => $rec_offset,
2456
			'sheetState' => $sheetState,
2457
			'sheetType' => $sheetType,
2458
		);
2459
	}
2460
2461
2462
	/**
2463
	 * Read EXTERNALBOOK record
2464
	 */
2465
	private function _readExternalBook()
2466
	{
2467
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2468
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2469
2470
		// move stream pointer to next record
2471
		$this->_pos += 4 + $length;
2472
2473
		// offset within record data
2474
		$offset = 0;
2475
2476
		// there are 4 types of records
2477
		if (strlen($recordData) > 4) {
2478
			// external reference
2479
			// offset: 0; size: 2; number of sheet names ($nm)
2480
			$nm = self::_GetInt2d($recordData, 0);
2481
			$offset += 2;
2482
2483
			// offset: 2; size: var; encoded URL without sheet name (Unicode string, 16-bit length)
2484
			$encodedUrlString = self::_readUnicodeStringLong(substr($recordData, 2));
2485
			$offset += $encodedUrlString['size'];
2486
2487
			// offset: var; size: var; list of $nm sheet names (Unicode strings, 16-bit length)
2488
			$externalSheetNames = array();
2489
			for ($i = 0; $i < $nm; ++$i) {
2490
				$externalSheetNameString = self::_readUnicodeStringLong(substr($recordData, $offset));
2491
				$externalSheetNames[] = $externalSheetNameString['value'];
2492
				$offset += $externalSheetNameString['size'];
2493
			}
2494
2495
			// store the record data
2496
			$this->_externalBooks[] = array(
2497
				'type' => 'external',
2498
				'encodedUrl' => $encodedUrlString['value'],
2499
				'externalSheetNames' => $externalSheetNames,
2500
			);
2501
2502
		} elseif (substr($recordData, 2, 2) == pack('CC', 0x01, 0x04)) {
2503
			// internal reference
2504
			// offset: 0; size: 2; number of sheet in this document
2505
			// offset: 2; size: 2; 0x01 0x04
2506
			$this->_externalBooks[] = array(
2507
				'type' => 'internal',
2508
			);
2509
		} elseif (substr($recordData, 0, 4) == pack('vCC', 0x0001, 0x01, 0x3A)) {
2510
			// add-in function
2511
			// offset: 0; size: 2; 0x0001
2512
			$this->_externalBooks[] = array(
2513
				'type' => 'addInFunction',
2514
			);
2515
		} elseif (substr($recordData, 0, 2) == pack('v', 0x0000)) {
2516
			// DDE links, OLE links
2517
			// offset: 0; size: 2; 0x0000
2518
			// offset: 2; size: var; encoded source document name
2519
			$this->_externalBooks[] = array(
2520
				'type' => 'DDEorOLE',
2521
			);
2522
		}
2523
	}
2524
2525
2526
	/**
2527
	 * Read EXTERNNAME record.
2528
	 */
2529
	private function _readExternName()
2530
	{
2531
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2532
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2533
2534
		// move stream pointer to next record
2535
		$this->_pos += 4 + $length;
2536
2537
		// external sheet references provided for named cells
2538
		if ($this->_version == self::XLS_BIFF8) {
2539
			// offset: 0; size: 2; options
2540
			$options = self::_GetInt2d($recordData, 0);
2541
2542
			// offset: 2; size: 2;
2543
2544
			// offset: 4; size: 2; not used
2545
2546
			// offset: 6; size: var
2547
			$nameString = self::_readUnicodeStringShort(substr($recordData, 6));
2548
2549
			// offset: var; size: var; formula data
2550
			$offset = 6 + $nameString['size'];
2551
			$formula = $this->_getFormulaFromStructure(substr($recordData, $offset));
2552
2553
			$this->_externalNames[] = array(
2554
				'name' => $nameString['value'],
2555
				'formula' => $formula,
2556
			);
2557
		}
2558
	}
2559
2560
2561
	/**
2562
	 * Read EXTERNSHEET record
2563
	 */
2564
	private function _readExternSheet()
2565
	{
2566
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2567
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2568
2569
		// move stream pointer to next record
2570
		$this->_pos += 4 + $length;
2571
2572
		// external sheet references provided for named cells
2573
		if ($this->_version == self::XLS_BIFF8) {
2574
			// offset: 0; size: 2; number of following ref structures
2575
			$nm = self::_GetInt2d($recordData, 0);
2576
			for ($i = 0; $i < $nm; ++$i) {
2577
				$this->_ref[] = array(
2578
					// offset: 2 + 6 * $i; index to EXTERNALBOOK record
2579
					'externalBookIndex' => self::_GetInt2d($recordData, 2 + 6 * $i),
2580
					// offset: 4 + 6 * $i; index to first sheet in EXTERNALBOOK record
2581
					'firstSheetIndex' => self::_GetInt2d($recordData, 4 + 6 * $i),
2582
					// offset: 6 + 6 * $i; index to last sheet in EXTERNALBOOK record
2583
					'lastSheetIndex' => self::_GetInt2d($recordData, 6 + 6 * $i),
2584
				);
2585
			}
2586
		}
2587
	}
2588
2589
2590
	/**
2591
	 * DEFINEDNAME
2592
	 *
2593
	 * This record is part of a Link Table. It contains the name
2594
	 * and the token array of an internal defined name. Token
2595
	 * arrays of defined names contain tokens with aberrant
2596
	 * token classes.
2597
	 *
2598
	 * --	"OpenOffice.org's Documentation of the Microsoft
2599
	 * 		Excel File Format"
2600
	 */
2601
	private function _readDefinedName()
2602
	{
2603
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2604
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2605
2606
		// move stream pointer to next record
2607
		$this->_pos += 4 + $length;
2608
2609
		if ($this->_version == self::XLS_BIFF8) {
2610
			// retrieves named cells
2611
2612
			// offset: 0; size: 2; option flags
2613
			$opts = self::_GetInt2d($recordData, 0);
2614
2615
				// bit: 5; mask: 0x0020; 0 = user-defined name, 1 = built-in-name
2616
				$isBuiltInName = (0x0020 & $opts) >> 5;
2617
2618
			// offset: 2; size: 1; keyboard shortcut
2619
2620
			// offset: 3; size: 1; length of the name (character count)
2621
			$nlen = ord($recordData{3});
2622
2623
			// offset: 4; size: 2; size of the formula data (it can happen that this is zero)
2624
			// note: there can also be additional data, this is not included in $flen
2625
			$flen = self::_GetInt2d($recordData, 4);
2626
2627
			// offset: 8; size: 2; 0=Global name, otherwise index to sheet (1-based)
2628
			$scope = self::_GetInt2d($recordData, 8);
2629
2630
			// offset: 14; size: var; Name (Unicode string without length field)
2631
			$string = self::_readUnicodeString(substr($recordData, 14), $nlen);
2632
2633
			// offset: var; size: $flen; formula data
2634
			$offset = 14 + $string['size'];
2635
			$formulaStructure = pack('v', $flen) . substr($recordData, $offset);
2636
2637
			try {
2638
				$formula = $this->_getFormulaFromStructure($formulaStructure);
2639
			} catch (Exception $e) {
2640
				$formula = '';
2641
			}
2642
2643
			$this->_definedname[] = array(
2644
				'isBuiltInName' => $isBuiltInName,
2645
				'name' => $string['value'],
2646
				'formula' => $formula,
2647
				'scope' => $scope,
2648
			);
2649
		}
2650
	}
2651
2652
2653
	/**
2654
	 * Read MSODRAWINGGROUP record
2655
	 */
2656 View Code Duplication
	private function _readMsoDrawingGroup()
2657
	{
2658
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2659
2660
		// get spliced record data
2661
		$splicedRecordData = $this->_getSplicedRecordData();
2662
		$recordData = $splicedRecordData['recordData'];
2663
2664
		$this->_drawingGroupData .= $recordData;
2665
	}
2666
2667
2668
	/**
2669
	 * SST - Shared String Table
2670
	 *
2671
	 * This record contains a list of all strings used anywhere
2672
	 * in the workbook. Each string occurs only once. The
2673
	 * workbook uses indexes into the list to reference the
2674
	 * strings.
2675
	 *
2676
	 * --	"OpenOffice.org's Documentation of the Microsoft
2677
	 * 		Excel File Format"
2678
	 **/
2679
	private function _readSst()
2680
	{
2681
		// offset within (spliced) record data
2682
		$pos = 0;
2683
2684
		// get spliced record data
2685
		$splicedRecordData = $this->_getSplicedRecordData();
2686
2687
		$recordData = $splicedRecordData['recordData'];
2688
		$spliceOffsets = $splicedRecordData['spliceOffsets'];
2689
2690
		// offset: 0; size: 4; total number of strings in the workbook
2691
		$pos += 4;
2692
2693
		// offset: 4; size: 4; number of following strings ($nm)
2694
		$nm = self::_GetInt4d($recordData, 4);
2695
		$pos += 4;
2696
2697
		// loop through the Unicode strings (16-bit length)
2698
		for ($i = 0; $i < $nm; ++$i) {
2699
2700
			// number of characters in the Unicode string
2701
			$numChars = self::_GetInt2d($recordData, $pos);
2702
			$pos += 2;
2703
2704
			// option flags
2705
			$optionFlags = ord($recordData{$pos});
2706
			++$pos;
2707
2708
			// bit: 0; mask: 0x01; 0 = compressed; 1 = uncompressed
2709
			$isCompressed = (($optionFlags & 0x01) == 0) ;
2710
2711
			// bit: 2; mask: 0x02; 0 = ordinary; 1 = Asian phonetic
2712
			$hasAsian = (($optionFlags & 0x04) != 0);
2713
2714
			// bit: 3; mask: 0x03; 0 = ordinary; 1 = Rich-Text
2715
			$hasRichText = (($optionFlags & 0x08) != 0);
2716
2717
			if ($hasRichText) {
2718
				// number of Rich-Text formatting runs
2719
				$formattingRuns = self::_GetInt2d($recordData, $pos);
2720
				$pos += 2;
2721
			}
2722
2723
			if ($hasAsian) {
2724
				// size of Asian phonetic setting
2725
				$extendedRunLength = self::_GetInt4d($recordData, $pos);
2726
				$pos += 4;
2727
			}
2728
2729
			// expected byte length of character array if not split
2730
			$len = ($isCompressed) ? $numChars : $numChars * 2;
2731
2732
			// look up limit position
2733
			foreach ($spliceOffsets as $spliceOffset) {
2734
				// it can happen that the string is empty, therefore we need
2735
				// <= and not just <
2736
				if ($pos <= $spliceOffset) {
2737
					$limitpos = $spliceOffset;
2738
					break;
2739
				}
2740
			}
2741
2742
			if ($pos + $len <= $limitpos) {
2743
				// character array is not split between records
2744
2745
				$retstr = substr($recordData, $pos, $len);
2746
				$pos += $len;
2747
2748
			} else {
2749
				// character array is split between records
2750
2751
				// first part of character array
2752
				$retstr = substr($recordData, $pos, $limitpos - $pos);
0 ignored issues
show
Bug introduced by
The variable $limitpos does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2753
2754
				$bytesRead = $limitpos - $pos;
2755
2756
				// remaining characters in Unicode string
2757
				$charsLeft = $numChars - (($isCompressed) ? $bytesRead : ($bytesRead / 2));
2758
2759
				$pos = $limitpos;
2760
2761
				// keep reading the characters
2762
				while ($charsLeft > 0) {
2763
2764
					// look up next limit position, in case the string span more than one continue record
2765
					foreach ($spliceOffsets as $spliceOffset) {
2766
						if ($pos < $spliceOffset) {
2767
							$limitpos = $spliceOffset;
2768
							break;
2769
						}
2770
					}
2771
2772
					// repeated option flags
2773
					// OpenOffice.org documentation 5.21
2774
					$option = ord($recordData{$pos});
2775
					++$pos;
2776
2777
					if ($isCompressed && ($option == 0)) {
2778
						// 1st fragment compressed
2779
						// this fragment compressed
2780
						$len = min($charsLeft, $limitpos - $pos);
2781
						$retstr .= substr($recordData, $pos, $len);
2782
						$charsLeft -= $len;
2783
						$isCompressed = true;
2784
2785
					} elseif (!$isCompressed && ($option != 0)) {
2786
						// 1st fragment uncompressed
2787
						// this fragment uncompressed
2788
						$len = min($charsLeft * 2, $limitpos - $pos);
2789
						$retstr .= substr($recordData, $pos, $len);
2790
						$charsLeft -= $len / 2;
2791
						$isCompressed = false;
2792
2793
					} elseif (!$isCompressed && ($option == 0)) {
2794
						// 1st fragment uncompressed
2795
						// this fragment compressed
2796
						$len = min($charsLeft, $limitpos - $pos);
2797
						for ($j = 0; $j < $len; ++$j) {
2798
							$retstr .= $recordData{$pos + $j} . chr(0);
2799
						}
2800
						$charsLeft -= $len;
2801
						$isCompressed = false;
2802
2803
					} else {
2804
						// 1st fragment compressed
2805
						// this fragment uncompressed
2806
						$newstr = '';
2807
						for ($j = 0; $j < strlen($retstr); ++$j) {
2808
							$newstr .= $retstr[$j] . chr(0);
2809
						}
2810
						$retstr = $newstr;
2811
						$len = min($charsLeft * 2, $limitpos - $pos);
2812
						$retstr .= substr($recordData, $pos, $len);
2813
						$charsLeft -= $len / 2;
2814
						$isCompressed = false;
2815
					}
2816
2817
					$pos += $len;
2818
				}
2819
			}
2820
2821
			// convert to UTF-8
2822
			$retstr = self::_encodeUTF16($retstr, $isCompressed);
2823
2824
			// read additional Rich-Text information, if any
2825
			$fmtRuns = array();
2826
			if ($hasRichText) {
2827
				// list of formatting runs
2828
				for ($j = 0; $j < $formattingRuns; ++$j) {
0 ignored issues
show
Bug introduced by
The variable $formattingRuns does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2829
					// first formatted character; zero-based
2830
					$charPos = self::_GetInt2d($recordData, $pos + $j * 4);
2831
2832
					// index to font record
2833
					$fontIndex = self::_GetInt2d($recordData, $pos + 2 + $j * 4);
2834
2835
					$fmtRuns[] = array(
2836
						'charPos' => $charPos,
2837
						'fontIndex' => $fontIndex,
2838
					);
2839
				}
2840
				$pos += 4 * $formattingRuns;
2841
			}
2842
2843
			// read additional Asian phonetics information, if any
2844
			if ($hasAsian) {
2845
				// For Asian phonetic settings, we skip the extended string data
2846
				$pos += $extendedRunLength;
0 ignored issues
show
Bug introduced by
The variable $extendedRunLength does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2847
			}
2848
2849
			// store the shared sting
2850
			$this->_sst[] = array(
2851
				'value' => $retstr,
2852
				'fmtRuns' => $fmtRuns,
2853
			);
2854
		}
2855
2856
		// _getSplicedRecordData() takes care of moving current position in data stream
2857
	}
2858
2859
2860
	/**
2861
	 * Read PRINTGRIDLINES record
2862
	 */
2863
	private function _readPrintGridlines()
2864
	{
2865
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2866
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2867
2868
		// move stream pointer to next record
2869
		$this->_pos += 4 + $length;
2870
2871
		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
2872
			// offset: 0; size: 2; 0 = do not print sheet grid lines; 1 = print sheet gridlines
2873
			$printGridlines = (bool) self::_GetInt2d($recordData, 0);
2874
			$this->_phpSheet->setPrintGridlines($printGridlines);
2875
		}
2876
	}
2877
2878
2879
	/**
2880
	 * Read DEFAULTROWHEIGHT record
2881
	 */
2882
	private function _readDefaultRowHeight()
2883
	{
2884
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2885
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2886
2887
		// move stream pointer to next record
2888
		$this->_pos += 4 + $length;
2889
2890
		// offset: 0; size: 2; option flags
2891
		// offset: 2; size: 2; default height for unused rows, (twips 1/20 point)
2892
		$height = self::_GetInt2d($recordData, 2);
2893
		$this->_phpSheet->getDefaultRowDimension()->setRowHeight($height / 20);
2894
	}
2895
2896
2897
	/**
2898
	 * Read SHEETPR record
2899
	 */
2900
	private function _readSheetPr()
2901
	{
2902
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2903
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2904
2905
		// move stream pointer to next record
2906
		$this->_pos += 4 + $length;
2907
2908
		// offset: 0; size: 2
2909
2910
		// bit: 6; mask: 0x0040; 0 = outline buttons above outline group
2911
		$isSummaryBelow = (0x0040 & self::_GetInt2d($recordData, 0)) >> 6;
2912
		$this->_phpSheet->setShowSummaryBelow($isSummaryBelow);
2913
2914
		// bit: 7; mask: 0x0080; 0 = outline buttons left of outline group
2915
		$isSummaryRight = (0x0080 & self::_GetInt2d($recordData, 0)) >> 7;
2916
		$this->_phpSheet->setShowSummaryRight($isSummaryRight);
2917
2918
		// bit: 8; mask: 0x100; 0 = scale printout in percent, 1 = fit printout to number of pages
2919
		// this corresponds to radio button setting in page setup dialog in Excel
2920
		$this->_isFitToPages = (bool) ((0x0100 & self::_GetInt2d($recordData, 0)) >> 8);
2921
	}
2922
2923
2924
	/**
2925
	 * Read HORIZONTALPAGEBREAKS record
2926
	 */
2927 View Code Duplication
	private function _readHorizontalPageBreaks()
2928
	{
2929
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2930
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2931
2932
		// move stream pointer to next record
2933
		$this->_pos += 4 + $length;
2934
2935
		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
2936
2937
			// offset: 0; size: 2; number of the following row index structures
2938
			$nm = self::_GetInt2d($recordData, 0);
2939
2940
			// offset: 2; size: 6 * $nm; list of $nm row index structures
2941
			for ($i = 0; $i < $nm; ++$i) {
2942
				$r = self::_GetInt2d($recordData, 2 + 6 * $i);
2943
				$cf = self::_GetInt2d($recordData, 2 + 6 * $i + 2);
2944
				$cl = self::_GetInt2d($recordData, 2 + 6 * $i + 4);
2945
2946
				// not sure why two column indexes are necessary?
2947
				$this->_phpSheet->setBreakByColumnAndRow($cf, $r, PHPExcel_Worksheet::BREAK_ROW);
2948
			}
2949
		}
2950
	}
2951
2952
2953
	/**
2954
	 * Read VERTICALPAGEBREAKS record
2955
	 */
2956 View Code Duplication
	private function _readVerticalPageBreaks()
2957
	{
2958
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2959
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2960
2961
		// move stream pointer to next record
2962
		$this->_pos += 4 + $length;
2963
2964
		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
2965
			// offset: 0; size: 2; number of the following column index structures
2966
			$nm = self::_GetInt2d($recordData, 0);
2967
2968
			// offset: 2; size: 6 * $nm; list of $nm row index structures
2969
			for ($i = 0; $i < $nm; ++$i) {
2970
				$c = self::_GetInt2d($recordData, 2 + 6 * $i);
2971
				$rf = self::_GetInt2d($recordData, 2 + 6 * $i + 2);
2972
				$rl = self::_GetInt2d($recordData, 2 + 6 * $i + 4);
2973
2974
				// not sure why two row indexes are necessary?
2975
				$this->_phpSheet->setBreakByColumnAndRow($c, $rf, PHPExcel_Worksheet::BREAK_COLUMN);
2976
			}
2977
		}
2978
	}
2979
2980
2981
	/**
2982
	 * Read HEADER record
2983
	 */
2984 View Code Duplication
	private function _readHeader()
2985
	{
2986
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
2987
		$recordData = substr($this->_data, $this->_pos + 4, $length);
2988
2989
		// move stream pointer to next record
2990
		$this->_pos += 4 + $length;
2991
2992
		if (!$this->_readDataOnly) {
2993
			// offset: 0; size: var
2994
			// realized that $recordData can be empty even when record exists
2995
			if ($recordData) {
2996
				if ($this->_version == self::XLS_BIFF8) {
2997
					$string = self::_readUnicodeStringLong($recordData);
2998
				} else {
2999
					$string = $this->_readByteStringShort($recordData);
3000
				}
3001
3002
				$this->_phpSheet->getHeaderFooter()->setOddHeader($string['value']);
3003
				$this->_phpSheet->getHeaderFooter()->setEvenHeader($string['value']);
3004
			}
3005
		}
3006
	}
3007
3008
3009
	/**
3010
	 * Read FOOTER record
3011
	 */
3012 View Code Duplication
	private function _readFooter()
3013
	{
3014
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3015
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3016
3017
		// move stream pointer to next record
3018
		$this->_pos += 4 + $length;
3019
3020
		if (!$this->_readDataOnly) {
3021
			// offset: 0; size: var
3022
			// realized that $recordData can be empty even when record exists
3023
			if ($recordData) {
3024
				if ($this->_version == self::XLS_BIFF8) {
3025
					$string = self::_readUnicodeStringLong($recordData);
3026
				} else {
3027
					$string = $this->_readByteStringShort($recordData);
3028
				}
3029
				$this->_phpSheet->getHeaderFooter()->setOddFooter($string['value']);
3030
				$this->_phpSheet->getHeaderFooter()->setEvenFooter($string['value']);
3031
			}
3032
		}
3033
	}
3034
3035
3036
	/**
3037
	 * Read HCENTER record
3038
	 */
3039
	private function _readHcenter()
3040
	{
3041
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3042
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3043
3044
		// move stream pointer to next record
3045
		$this->_pos += 4 + $length;
3046
3047
		if (!$this->_readDataOnly) {
3048
			// offset: 0; size: 2; 0 = print sheet left aligned, 1 = print sheet centered horizontally
3049
			$isHorizontalCentered = (bool) self::_GetInt2d($recordData, 0);
3050
3051
			$this->_phpSheet->getPageSetup()->setHorizontalCentered($isHorizontalCentered);
3052
		}
3053
	}
3054
3055
3056
	/**
3057
	 * Read VCENTER record
3058
	 */
3059
	private function _readVcenter()
3060
	{
3061
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3062
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3063
3064
		// move stream pointer to next record
3065
		$this->_pos += 4 + $length;
3066
3067
		if (!$this->_readDataOnly) {
3068
			// offset: 0; size: 2; 0 = print sheet aligned at top page border, 1 = print sheet vertically centered
3069
			$isVerticalCentered = (bool) self::_GetInt2d($recordData, 0);
3070
3071
			$this->_phpSheet->getPageSetup()->setVerticalCentered($isVerticalCentered);
3072
		}
3073
	}
3074
3075
3076
	/**
3077
	 * Read LEFTMARGIN record
3078
	 */
3079
	private function _readLeftMargin()
3080
	{
3081
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3082
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3083
3084
		// move stream pointer to next record
3085
		$this->_pos += 4 + $length;
3086
3087
		if (!$this->_readDataOnly) {
3088
			// offset: 0; size: 8
3089
			$this->_phpSheet->getPageMargins()->setLeft(self::_extractNumber($recordData));
3090
		}
3091
	}
3092
3093
3094
	/**
3095
	 * Read RIGHTMARGIN record
3096
	 */
3097
	private function _readRightMargin()
3098
	{
3099
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3100
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3101
3102
		// move stream pointer to next record
3103
		$this->_pos += 4 + $length;
3104
3105
		if (!$this->_readDataOnly) {
3106
			// offset: 0; size: 8
3107
			$this->_phpSheet->getPageMargins()->setRight(self::_extractNumber($recordData));
3108
		}
3109
	}
3110
3111
3112
	/**
3113
	 * Read TOPMARGIN record
3114
	 */
3115
	private function _readTopMargin()
3116
	{
3117
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3118
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3119
3120
		// move stream pointer to next record
3121
		$this->_pos += 4 + $length;
3122
3123
		if (!$this->_readDataOnly) {
3124
			// offset: 0; size: 8
3125
			$this->_phpSheet->getPageMargins()->setTop(self::_extractNumber($recordData));
3126
		}
3127
	}
3128
3129
3130
	/**
3131
	 * Read BOTTOMMARGIN record
3132
	 */
3133
	private function _readBottomMargin()
3134
	{
3135
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3136
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3137
3138
		// move stream pointer to next record
3139
		$this->_pos += 4 + $length;
3140
3141
		if (!$this->_readDataOnly) {
3142
			// offset: 0; size: 8
3143
			$this->_phpSheet->getPageMargins()->setBottom(self::_extractNumber($recordData));
3144
		}
3145
	}
3146
3147
3148
	/**
3149
	 * Read PAGESETUP record
3150
	 */
3151
	private function _readPageSetup()
3152
	{
3153
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3154
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3155
3156
		// move stream pointer to next record
3157
		$this->_pos += 4 + $length;
3158
3159
		if (!$this->_readDataOnly) {
3160
			// offset: 0; size: 2; paper size
3161
			$paperSize = self::_GetInt2d($recordData, 0);
3162
3163
			// offset: 2; size: 2; scaling factor
3164
			$scale = self::_GetInt2d($recordData, 2);
3165
3166
			// offset: 6; size: 2; fit worksheet width to this number of pages, 0 = use as many as needed
3167
			$fitToWidth = self::_GetInt2d($recordData, 6);
3168
3169
			// offset: 8; size: 2; fit worksheet height to this number of pages, 0 = use as many as needed
3170
			$fitToHeight = self::_GetInt2d($recordData, 8);
3171
3172
			// offset: 10; size: 2; option flags
3173
3174
				// bit: 1; mask: 0x0002; 0=landscape, 1=portrait
3175
				$isPortrait = (0x0002 & self::_GetInt2d($recordData, 10)) >> 1;
3176
3177
				// bit: 2; mask: 0x0004; 1= paper size, scaling factor, paper orient. not init
3178
				// when this bit is set, do not use flags for those properties
3179
				$isNotInit = (0x0004 & self::_GetInt2d($recordData, 10)) >> 2;
3180
3181
			if (!$isNotInit) {
3182
				$this->_phpSheet->getPageSetup()->setPaperSize($paperSize);
3183
				switch ($isPortrait) {
3184
				case 0: $this->_phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE); break;
3185
				case 1: $this->_phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_PORTRAIT); break;
3186
				}
3187
3188
				$this->_phpSheet->getPageSetup()->setScale($scale, false);
3189
				$this->_phpSheet->getPageSetup()->setFitToPage((bool) $this->_isFitToPages);
3190
				$this->_phpSheet->getPageSetup()->setFitToWidth($fitToWidth, false);
3191
				$this->_phpSheet->getPageSetup()->setFitToHeight($fitToHeight, false);
3192
			}
3193
3194
			// offset: 16; size: 8; header margin (IEEE 754 floating-point value)
3195
			$marginHeader = self::_extractNumber(substr($recordData, 16, 8));
3196
			$this->_phpSheet->getPageMargins()->setHeader($marginHeader);
3197
3198
			// offset: 24; size: 8; footer margin (IEEE 754 floating-point value)
3199
			$marginFooter = self::_extractNumber(substr($recordData, 24, 8));
3200
			$this->_phpSheet->getPageMargins()->setFooter($marginFooter);
3201
		}
3202
	}
3203
3204
3205
	/**
3206
	 * PROTECT - Sheet protection (BIFF2 through BIFF8)
3207
	 *   if this record is omitted, then it also means no sheet protection
3208
	 */
3209
	private function _readProtect()
3210
	{
3211
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3212
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3213
3214
		// move stream pointer to next record
3215
		$this->_pos += 4 + $length;
3216
3217
		if ($this->_readDataOnly) {
3218
			return;
3219
		}
3220
3221
		// offset: 0; size: 2;
3222
3223
		// bit 0, mask 0x01; 1 = sheet is protected
3224
		$bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
3225
		$this->_phpSheet->getProtection()->setSheet((bool)$bool);
3226
	}
3227
3228
3229
	/**
3230
	 * SCENPROTECT
3231
	 */
3232
	private function _readScenProtect()
3233
	{
3234
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3235
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3236
3237
		// move stream pointer to next record
3238
		$this->_pos += 4 + $length;
3239
3240
		if ($this->_readDataOnly) {
3241
			return;
3242
		}
3243
3244
		// offset: 0; size: 2;
3245
3246
		// bit: 0, mask 0x01; 1 = scenarios are protected
3247
		$bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
3248
3249
		$this->_phpSheet->getProtection()->setScenarios((bool)$bool);
3250
	}
3251
3252
3253
	/**
3254
	 * OBJECTPROTECT
3255
	 */
3256
	private function _readObjectProtect()
3257
	{
3258
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3259
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3260
3261
		// move stream pointer to next record
3262
		$this->_pos += 4 + $length;
3263
3264
		if ($this->_readDataOnly) {
3265
			return;
3266
		}
3267
3268
		// offset: 0; size: 2;
3269
3270
		// bit: 0, mask 0x01; 1 = objects are protected
3271
		$bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
3272
3273
		$this->_phpSheet->getProtection()->setObjects((bool)$bool);
3274
	}
3275
3276
3277
	/**
3278
	 * PASSWORD - Sheet protection (hashed) password (BIFF2 through BIFF8)
3279
	 */
3280
	private function _readPassword()
3281
	{
3282
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3283
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3284
3285
		// move stream pointer to next record
3286
		$this->_pos += 4 + $length;
3287
3288
		if (!$this->_readDataOnly) {
3289
			// offset: 0; size: 2; 16-bit hash value of password
3290
			$password = strtoupper(dechex(self::_GetInt2d($recordData, 0))); // the hashed password
3291
			$this->_phpSheet->getProtection()->setPassword($password, true);
3292
		}
3293
	}
3294
3295
3296
	/**
3297
	 * Read DEFCOLWIDTH record
3298
	 */
3299
	private function _readDefColWidth()
3300
	{
3301
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3302
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3303
3304
		// move stream pointer to next record
3305
		$this->_pos += 4 + $length;
3306
3307
		// offset: 0; size: 2; default column width
3308
		$width = self::_GetInt2d($recordData, 0);
3309
		if ($width != 8) {
3310
			$this->_phpSheet->getDefaultColumnDimension()->setWidth($width);
3311
		}
3312
	}
3313
3314
3315
	/**
3316
	 * Read COLINFO record
3317
	 */
3318
	private function _readColInfo()
3319
	{
3320
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3321
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3322
3323
		// move stream pointer to next record
3324
		$this->_pos += 4 + $length;
3325
3326
		if (!$this->_readDataOnly) {
3327
			// offset: 0; size: 2; index to first column in range
3328
			$fc = self::_GetInt2d($recordData, 0); // first column index
3329
3330
			// offset: 2; size: 2; index to last column in range
3331
			$lc = self::_GetInt2d($recordData, 2); // first column index
3332
3333
			// offset: 4; size: 2; width of the column in 1/256 of the width of the zero character
3334
			$width = self::_GetInt2d($recordData, 4);
3335
3336
			// offset: 6; size: 2; index to XF record for default column formatting
3337
			$xfIndex = self::_GetInt2d($recordData, 6);
3338
3339
			// offset: 8; size: 2; option flags
3340
3341
				// bit: 0; mask: 0x0001; 1= columns are hidden
3342
				$isHidden = (0x0001 & self::_GetInt2d($recordData, 8)) >> 0;
3343
3344
				// bit: 10-8; mask: 0x0700; outline level of the columns (0 = no outline)
3345
				$level = (0x0700 & self::_GetInt2d($recordData, 8)) >> 8;
3346
3347
				// bit: 12; mask: 0x1000; 1 = collapsed
3348
				$isCollapsed = (0x1000 & self::_GetInt2d($recordData, 8)) >> 12;
3349
3350
			// offset: 10; size: 2; not used
3351
3352
			for ($i = $fc; $i <= $lc; ++$i) {
3353
				if ($lc == 255 || $lc == 256) {
3354
					$this->_phpSheet->getDefaultColumnDimension()->setWidth($width / 256);
3355
					break;
3356
				}
3357
				$this->_phpSheet->getColumnDimensionByColumn($i)->setWidth($width / 256);
3358
				$this->_phpSheet->getColumnDimensionByColumn($i)->setVisible(!$isHidden);
3359
				$this->_phpSheet->getColumnDimensionByColumn($i)->setOutlineLevel($level);
3360
				$this->_phpSheet->getColumnDimensionByColumn($i)->setCollapsed($isCollapsed);
3361
				$this->_phpSheet->getColumnDimensionByColumn($i)->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3362
			}
3363
		}
3364
	}
3365
3366
3367
	/**
3368
	 * ROW
3369
	 *
3370
	 * This record contains the properties of a single row in a
3371
	 * sheet. Rows and cells in a sheet are divided into blocks
3372
	 * of 32 rows.
3373
	 *
3374
	 * --	"OpenOffice.org's Documentation of the Microsoft
3375
	 * 		Excel File Format"
3376
	 */
3377
	private function _readRow()
3378
	{
3379
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3380
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3381
3382
		// move stream pointer to next record
3383
		$this->_pos += 4 + $length;
3384
3385
		if (!$this->_readDataOnly) {
3386
			// offset: 0; size: 2; index of this row
3387
			$r = self::_GetInt2d($recordData, 0);
3388
3389
			// offset: 2; size: 2; index to column of the first cell which is described by a cell record
3390
3391
			// offset: 4; size: 2; index to column of the last cell which is described by a cell record, increased by 1
3392
3393
			// offset: 6; size: 2;
3394
3395
			// bit: 14-0; mask: 0x7FFF; height of the row, in twips = 1/20 of a point
3396
			$height = (0x7FFF & self::_GetInt2d($recordData, 6)) >> 0;
3397
3398
			// bit: 15: mask: 0x8000; 0 = row has custom height; 1= row has default height
3399
			$useDefaultHeight = (0x8000 & self::_GetInt2d($recordData, 6)) >> 15;
3400
3401
			if (!$useDefaultHeight) {
3402
				$this->_phpSheet->getRowDimension($r + 1)->setRowHeight($height / 20);
3403
			}
3404
3405
			// offset: 8; size: 2; not used
3406
3407
			// offset: 10; size: 2; not used in BIFF5-BIFF8
3408
3409
			// offset: 12; size: 4; option flags and default row formatting
3410
3411
			// bit: 2-0: mask: 0x00000007; outline level of the row
3412
			$level = (0x00000007 & self::_GetInt4d($recordData, 12)) >> 0;
3413
			$this->_phpSheet->getRowDimension($r + 1)->setOutlineLevel($level);
3414
3415
			// bit: 4; mask: 0x00000010; 1 = outline group start or ends here... and is collapsed
3416
			$isCollapsed = (0x00000010 & self::_GetInt4d($recordData, 12)) >> 4;
3417
			$this->_phpSheet->getRowDimension($r + 1)->setCollapsed($isCollapsed);
3418
3419
			// bit: 5; mask: 0x00000020; 1 = row is hidden
3420
			$isHidden = (0x00000020 & self::_GetInt4d($recordData, 12)) >> 5;
3421
			$this->_phpSheet->getRowDimension($r + 1)->setVisible(!$isHidden);
3422
3423
			// bit: 7; mask: 0x00000080; 1 = row has explicit format
3424
			$hasExplicitFormat = (0x00000080 & self::_GetInt4d($recordData, 12)) >> 7;
3425
3426
			// bit: 27-16; mask: 0x0FFF0000; only applies when hasExplicitFormat = 1; index to XF record
3427
			$xfIndex = (0x0FFF0000 & self::_GetInt4d($recordData, 12)) >> 16;
3428
3429
			if ($hasExplicitFormat) {
3430
				$this->_phpSheet->getRowDimension($r + 1)->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3431
			}
3432
		}
3433
	}
3434
3435
3436
	/**
3437
	 * Read RK record
3438
	 * This record represents a cell that contains an RK value
3439
	 * (encoded integer or floating-point value). If a
3440
	 * floating-point value cannot be encoded to an RK value,
3441
	 * a NUMBER record will be written. This record replaces the
3442
	 * record INTEGER written in BIFF2.
3443
	 *
3444
	 * --	"OpenOffice.org's Documentation of the Microsoft
3445
	 * 		Excel File Format"
3446
	 */
3447 View Code Duplication
	private function _readRk()
3448
	{
3449
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3450
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3451
3452
		// move stream pointer to next record
3453
		$this->_pos += 4 + $length;
3454
3455
		// offset: 0; size: 2; index to row
3456
		$row = self::_GetInt2d($recordData, 0);
3457
3458
		// offset: 2; size: 2; index to column
3459
		$column = self::_GetInt2d($recordData, 2);
3460
		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3461
3462
		// Read cell?
3463
		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3464
			// offset: 4; size: 2; index to XF record
3465
			$xfIndex = self::_GetInt2d($recordData, 4);
3466
3467
			// offset: 6; size: 4; RK value
3468
			$rknum = self::_GetInt4d($recordData, 6);
3469
			$numValue = self::_GetIEEE754($rknum);
3470
3471
			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3472
			if (!$this->_readDataOnly) {
3473
				// add style information
3474
				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3475
			}
3476
3477
			// add cell
3478
			$cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
3479
		}
3480
	}
3481
3482
3483
	/**
3484
	 * Read LABELSST record
3485
	 * This record represents a cell that contains a string. It
3486
	 * replaces the LABEL record and RSTRING record used in
3487
	 * BIFF2-BIFF5.
3488
	 *
3489
	 * --	"OpenOffice.org's Documentation of the Microsoft
3490
	 * 		Excel File Format"
3491
	 */
3492
	private function _readLabelSst()
3493
	{
3494
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3495
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3496
3497
		// move stream pointer to next record
3498
		$this->_pos += 4 + $length;
3499
3500
		// offset: 0; size: 2; index to row
3501
		$row = self::_GetInt2d($recordData, 0);
3502
3503
		// offset: 2; size: 2; index to column
3504
		$column = self::_GetInt2d($recordData, 2);
3505
		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3506
3507
		// Read cell?
3508
		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3509
			// offset: 4; size: 2; index to XF record
3510
			$xfIndex = self::_GetInt2d($recordData, 4);
3511
3512
			// offset: 6; size: 4; index to SST record
3513
			$index = self::_GetInt4d($recordData, 6);
3514
3515
			// add cell
3516
			if (($fmtRuns = $this->_sst[$index]['fmtRuns']) && !$this->_readDataOnly) {
3517
				// then we should treat as rich text
3518
				$richText = new PHPExcel_RichText();
3519
				$charPos = 0;
3520
				$sstCount = count($this->_sst[$index]['fmtRuns']);
3521
				for ($i = 0; $i <= $sstCount; ++$i) {
3522
					if (isset($fmtRuns[$i])) {
3523
						$text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, $fmtRuns[$i]['charPos'] - $charPos);
3524
						$charPos = $fmtRuns[$i]['charPos'];
3525
					} else {
3526
						$text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, PHPExcel_Shared_String::CountCharacters($this->_sst[$index]['value']));
3527
					}
3528
3529
					if (PHPExcel_Shared_String::CountCharacters($text) > 0) {
3530
						if ($i == 0) { // first text run, no style
3531
							$richText->createText($text);
3532
						} else {
3533
							$textRun = $richText->createTextRun($text);
3534
							if (isset($fmtRuns[$i - 1])) {
3535
								if ($fmtRuns[$i - 1]['fontIndex'] < 4) {
3536
									$fontIndex = $fmtRuns[$i - 1]['fontIndex'];
3537
								} else {
3538
									// this has to do with that index 4 is omitted in all BIFF versions for some strange reason
3539
									// check the OpenOffice documentation of the FONT record
3540
									$fontIndex = $fmtRuns[$i - 1]['fontIndex'] - 1;
3541
								}
3542
								$textRun->setFont(clone $this->_objFonts[$fontIndex]);
3543
							}
3544
						}
3545
					}
3546
				}
3547
				$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3548
				$cell->setValueExplicit($richText, PHPExcel_Cell_DataType::TYPE_STRING);
3549
			} else {
3550
				$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3551
				$cell->setValueExplicit($this->_sst[$index]['value'], PHPExcel_Cell_DataType::TYPE_STRING);
3552
			}
3553
3554
			if (!$this->_readDataOnly) {
3555
				// add style information
3556
				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3557
			}
3558
		}
3559
	}
3560
3561
3562
	/**
3563
	 * Read MULRK record
3564
	 * This record represents a cell range containing RK value
3565
	 * cells. All cells are located in the same row.
3566
	 *
3567
	 * --	"OpenOffice.org's Documentation of the Microsoft
3568
	 * 		Excel File Format"
3569
	 */
3570
	private function _readMulRk()
3571
	{
3572
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3573
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3574
3575
		// move stream pointer to next record
3576
		$this->_pos += 4 + $length;
3577
3578
		// offset: 0; size: 2; index to row
3579
		$row = self::_GetInt2d($recordData, 0);
3580
3581
		// offset: 2; size: 2; index to first column
3582
		$colFirst = self::_GetInt2d($recordData, 2);
3583
3584
		// offset: var; size: 2; index to last column
3585
		$colLast = self::_GetInt2d($recordData, $length - 2);
3586
		$columns = $colLast - $colFirst + 1;
3587
3588
		// offset within record data
3589
		$offset = 4;
3590
3591
		for ($i = 0; $i < $columns; ++$i) {
3592
			$columnString = PHPExcel_Cell::stringFromColumnIndex($colFirst + $i);
3593
3594
			// Read cell?
3595
			if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3596
3597
				// offset: var; size: 2; index to XF record
3598
				$xfIndex = self::_GetInt2d($recordData, $offset);
3599
3600
				// offset: var; size: 4; RK value
3601
				$numValue = self::_GetIEEE754(self::_GetInt4d($recordData, $offset + 2));
3602
				$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3603
				if (!$this->_readDataOnly) {
3604
					// add style
3605
					$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3606
				}
3607
3608
				// add cell value
3609
				$cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
3610
			}
3611
3612
			$offset += 6;
3613
		}
3614
	}
3615
3616
3617
	/**
3618
	 * Read NUMBER record
3619
	 * This record represents a cell that contains a
3620
	 * floating-point value.
3621
	 *
3622
	 * --	"OpenOffice.org's Documentation of the Microsoft
3623
	 * 		Excel File Format"
3624
	 */
3625 View Code Duplication
	private function _readNumber()
3626
	{
3627
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3628
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3629
3630
		// move stream pointer to next record
3631
		$this->_pos += 4 + $length;
3632
3633
		// offset: 0; size: 2; index to row
3634
		$row = self::_GetInt2d($recordData, 0);
3635
3636
		// offset: 2; size 2; index to column
3637
		$column = self::_GetInt2d($recordData, 2);
3638
		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3639
3640
		// Read cell?
3641
		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3642
			// offset 4; size: 2; index to XF record
3643
			$xfIndex = self::_GetInt2d($recordData, 4);
3644
3645
			$numValue = self::_extractNumber(substr($recordData, 6, 8));
3646
3647
			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3648
			if (!$this->_readDataOnly) {
3649
				// add cell style
3650
				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3651
			}
3652
3653
			// add cell value
3654
			$cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
3655
		}
3656
	}
3657
3658
3659
	/**
3660
	 * Read FORMULA record + perhaps a following STRING record if formula result is a string
3661
	 * This record contains the token array and the result of a
3662
	 * formula cell.
3663
	 *
3664
	 * --	"OpenOffice.org's Documentation of the Microsoft
3665
	 * 		Excel File Format"
3666
	 */
3667
	private function _readFormula()
3668
	{
3669
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3670
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3671
3672
		// move stream pointer to next record
3673
		$this->_pos += 4 + $length;
3674
3675
		// offset: 0; size: 2; row index
3676
		$row = self::_GetInt2d($recordData, 0);
3677
3678
		// offset: 2; size: 2; col index
3679
		$column = self::_GetInt2d($recordData, 2);
3680
		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3681
3682
		// offset: 20: size: variable; formula structure
3683
		$formulaStructure = substr($recordData, 20);
3684
3685
		// offset: 14: size: 2; option flags, recalculate always, recalculate on open etc.
3686
		$options = self::_GetInt2d($recordData, 14);
3687
3688
		// bit: 0; mask: 0x0001; 1 = recalculate always
3689
		// bit: 1; mask: 0x0002; 1 = calculate on open
3690
		// bit: 2; mask: 0x0008; 1 = part of a shared formula
3691
		$isPartOfSharedFormula = (bool) (0x0008 & $options);
3692
3693
		// WARNING:
3694
		// We can apparently not rely on $isPartOfSharedFormula. Even when $isPartOfSharedFormula = true
3695
		// the formula data may be ordinary formula data, therefore we need to check
3696
		// explicitly for the tExp token (0x01)
3697
		$isPartOfSharedFormula = $isPartOfSharedFormula && ord($formulaStructure{2}) == 0x01;
3698
3699
		if ($isPartOfSharedFormula) {
3700
			// part of shared formula which means there will be a formula with a tExp token and nothing else
3701
			// get the base cell, grab tExp token
3702
			$baseRow = self::_GetInt2d($formulaStructure, 3);
3703
			$baseCol = self::_GetInt2d($formulaStructure, 5);
3704
			$this->_baseCell = PHPExcel_Cell::stringFromColumnIndex($baseCol). ($baseRow + 1);
3705
		}
3706
3707
		// Read cell?
3708
		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3709
3710
			if ($isPartOfSharedFormula) {
3711
				// formula is added to this cell after the sheet has been read
3712
				$this->_sharedFormulaParts[$columnString . ($row + 1)] = $this->_baseCell;
3713
			}
3714
3715
			// offset: 16: size: 4; not used
3716
3717
			// offset: 4; size: 2; XF index
3718
			$xfIndex = self::_GetInt2d($recordData, 4);
3719
3720
			// offset: 6; size: 8; result of the formula
3721
			if ( (ord($recordData{6}) == 0)
3722
				&& (ord($recordData{12}) == 255)
3723
				&& (ord($recordData{13}) == 255) ) {
3724
3725
				// String formula. Result follows in appended STRING record
3726
				$dataType = PHPExcel_Cell_DataType::TYPE_STRING;
3727
3728
				// read possible SHAREDFMLA record
3729
				$code = self::_GetInt2d($this->_data, $this->_pos);
3730
				if ($code == self::XLS_Type_SHAREDFMLA) {
3731
					$this->_readSharedFmla();
3732
				}
3733
3734
				// read STRING record
3735
				$value = $this->_readString();
3736
3737 View Code Duplication
			} elseif ((ord($recordData{6}) == 1)
3738
				&& (ord($recordData{12}) == 255)
3739
				&& (ord($recordData{13}) == 255)) {
3740
3741
				// Boolean formula. Result is in +2; 0=false, 1=true
3742
				$dataType = PHPExcel_Cell_DataType::TYPE_BOOL;
3743
				$value = (bool) ord($recordData{8});
3744
3745
			} elseif ((ord($recordData{6}) == 2)
3746
				&& (ord($recordData{12}) == 255)
3747
				&& (ord($recordData{13}) == 255)) {
3748
3749
				// Error formula. Error code is in +2
3750
				$dataType = PHPExcel_Cell_DataType::TYPE_ERROR;
3751
				$value = self::_mapErrorCode(ord($recordData{8}));
3752
3753 View Code Duplication
			} elseif ((ord($recordData{6}) == 3)
3754
				&& (ord($recordData{12}) == 255)
3755
				&& (ord($recordData{13}) == 255)) {
3756
3757
				// Formula result is a null string
3758
				$dataType = PHPExcel_Cell_DataType::TYPE_NULL;
3759
				$value = '';
3760
3761
			} else {
3762
3763
				// forumla result is a number, first 14 bytes like _NUMBER record
3764
				$dataType = PHPExcel_Cell_DataType::TYPE_NUMERIC;
3765
				$value = self::_extractNumber(substr($recordData, 6, 8));
3766
3767
			}
3768
3769
			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3770
			if (!$this->_readDataOnly) {
3771
				// add cell style
3772
				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3773
			}
3774
3775
			// store the formula
3776
			if (!$isPartOfSharedFormula) {
3777
				// not part of shared formula
3778
				// add cell value. If we can read formula, populate with formula, otherwise just used cached value
3779
				try {
3780
					if ($this->_version != self::XLS_BIFF8) {
3781
						throw new Exception('Not BIFF8. Can only read BIFF8 formulas');
3782
					}
3783
					$formula = $this->_getFormulaFromStructure($formulaStructure); // get formula in human language
3784
					$cell->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
3785
3786
				} catch (Exception $e) {
3787
					$cell->setValueExplicit($value, $dataType);
3788
				}
3789
			} else {
3790
				if ($this->_version == self::XLS_BIFF8) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3791
					// do nothing at this point, formula id added later in the code
3792
				} else {
3793
					$cell->setValueExplicit($value, $dataType);
3794
				}
3795
			}
3796
3797
			// store the cached calculated value
3798
			$cell->setCalculatedValue($value);
3799
		}
3800
	}
3801
3802
3803
	/**
3804
	 * Read a SHAREDFMLA record. This function just stores the binary shared formula in the reader,
3805
	 * which usually contains relative references.
3806
	 * These will be used to construct the formula in each shared formula part after the sheet is read.
3807
	 */
3808
	private function _readSharedFmla()
3809
	{
3810
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3811
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3812
3813
		// move stream pointer to next record
3814
		$this->_pos += 4 + $length;
3815
3816
		// offset: 0, size: 6; cell range address of the area used by the shared formula, not used for anything
3817
		$cellRange = substr($recordData, 0, 6);
3818
		$cellRange = $this->_readBIFF5CellRangeAddressFixed($cellRange); // note: even BIFF8 uses BIFF5 syntax
3819
3820
		// offset: 6, size: 1; not used
3821
3822
		// offset: 7, size: 1; number of existing FORMULA records for this shared formula
3823
		$no = ord($recordData{7});
3824
3825
		// offset: 8, size: var; Binary token array of the shared formula
3826
		$formula = substr($recordData, 8);
3827
3828
		// at this point we only store the shared formula for later use
3829
		$this->_sharedFormulas[$this->_baseCell] = $formula;
3830
3831
	}
3832
3833
3834
	/**
3835
	 * Read a STRING record from current stream position and advance the stream pointer to next record
3836
	 * This record is used for storing result from FORMULA record when it is a string, and
3837
	 * it occurs directly after the FORMULA record
3838
	 *
3839
	 * @return string The string contents as UTF-8
3840
	 */
3841
	private function _readString()
3842
	{
3843
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3844
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3845
3846
		// move stream pointer to next record
3847
		$this->_pos += 4 + $length;
3848
3849
		if ($this->_version == self::XLS_BIFF8) {
3850
			$string = self::_readUnicodeStringLong($recordData);
3851
			$value = $string['value'];
3852
		} else {
3853
			$string = $this->_readByteStringLong($recordData);
3854
			$value = $string['value'];
3855
		}
3856
3857
		return $value;
3858
	}
3859
3860
3861
	/**
3862
	 * Read BOOLERR record
3863
	 * This record represents a Boolean value or error value
3864
	 * cell.
3865
	 *
3866
	 * --	"OpenOffice.org's Documentation of the Microsoft
3867
	 * 		Excel File Format"
3868
	 */
3869
	private function _readBoolErr()
3870
	{
3871
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3872
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3873
3874
		// move stream pointer to next record
3875
		$this->_pos += 4 + $length;
3876
3877
		// offset: 0; size: 2; row index
3878
		$row = self::_GetInt2d($recordData, 0);
3879
3880
		// offset: 2; size: 2; column index
3881
		$column = self::_GetInt2d($recordData, 2);
3882
		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3883
3884
		// Read cell?
3885
		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3886
			// offset: 4; size: 2; index to XF record
3887
			$xfIndex = self::_GetInt2d($recordData, 4);
3888
3889
			// offset: 6; size: 1; the boolean value or error value
3890
			$boolErr = ord($recordData{6});
3891
3892
			// offset: 7; size: 1; 0=boolean; 1=error
3893
			$isError = ord($recordData{7});
3894
3895
			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
3896
			switch ($isError) {
3897
				case 0: // boolean
3898
					$value = (bool) $boolErr;
3899
3900
					// add cell value
3901
					$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_BOOL);
3902
					break;
3903
3904
				case 1: // error type
3905
					$value = self::_mapErrorCode($boolErr);
3906
3907
					// add cell value
3908
					$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_ERROR);
3909
					break;
3910
			}
3911
3912
			if (!$this->_readDataOnly) {
3913
				// add cell style
3914
				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3915
			}
3916
		}
3917
	}
3918
3919
3920
	/**
3921
	 * Read MULBLANK record
3922
	 * This record represents a cell range of empty cells. All
3923
	 * cells are located in the same row
3924
	 *
3925
	 * --	"OpenOffice.org's Documentation of the Microsoft
3926
	 * 		Excel File Format"
3927
	 */
3928
	private function _readMulBlank()
3929
	{
3930
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3931
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3932
3933
		// move stream pointer to next record
3934
		$this->_pos += 4 + $length;
3935
3936
		// offset: 0; size: 2; index to row
3937
		$row = self::_GetInt2d($recordData, 0);
3938
3939
		// offset: 2; size: 2; index to first column
3940
		$fc = self::_GetInt2d($recordData, 2);
3941
3942
		// offset: 4; size: 2 x nc; list of indexes to XF records
3943
		// add style information
3944
		if (!$this->_readDataOnly) {
3945
			for ($i = 0; $i < $length / 2 - 3; ++$i) {
3946
				$columnString = PHPExcel_Cell::stringFromColumnIndex($fc + $i);
3947
3948
				// Read cell?
3949 View Code Duplication
				if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3950
					$xfIndex = self::_GetInt2d($recordData, 4 + 2 * $i);
3951
					$this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
3952
				}
3953
			}
3954
		}
3955
3956
		// offset: 6; size 2; index to last column (not needed)
3957
	}
3958
3959
3960
	/**
3961
	 * Read LABEL record
3962
	 * This record represents a cell that contains a string. In
3963
	 * BIFF8 it is usually replaced by the LABELSST record.
3964
	 * Excel still uses this record, if it copies unformatted
3965
	 * text cells to the clipboard.
3966
	 *
3967
	 * --	"OpenOffice.org's Documentation of the Microsoft
3968
	 * 		Excel File Format"
3969
	 */
3970
	private function _readLabel()
3971
	{
3972
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
3973
		$recordData = substr($this->_data, $this->_pos + 4, $length);
3974
3975
		// move stream pointer to next record
3976
		$this->_pos += 4 + $length;
3977
3978
		// offset: 0; size: 2; index to row
3979
		$row = self::_GetInt2d($recordData, 0);
3980
3981
		// offset: 2; size: 2; index to column
3982
		$column = self::_GetInt2d($recordData, 2);
3983
		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
3984
3985
		// Read cell?
3986
		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
3987
			// offset: 4; size: 2; XF index
3988
			$xfIndex = self::_GetInt2d($recordData, 4);
3989
3990
			// add cell value
3991
			// todo: what if string is very long? continue record
3992 View Code Duplication
			if ($this->_version == self::XLS_BIFF8) {
3993
				$string = self::_readUnicodeStringLong(substr($recordData, 6));
3994
				$value = $string['value'];
3995
			} else {
3996
				$string = $this->_readByteStringLong(substr($recordData, 6));
3997
				$value = $string['value'];
3998
			}
3999
			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
4000
			$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
4001
4002
			if (!$this->_readDataOnly) {
4003
				// add cell style
4004
				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
4005
			}
4006
		}
4007
	}
4008
4009
4010
	/**
4011
	 * Read BLANK record
4012
	 */
4013
	private function _readBlank()
4014
	{
4015
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4016
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4017
4018
		// move stream pointer to next record
4019
		$this->_pos += 4 + $length;
4020
4021
		// offset: 0; size: 2; row index
4022
		$row = self::_GetInt2d($recordData, 0);
4023
4024
		// offset: 2; size: 2; col index
4025
		$col = self::_GetInt2d($recordData, 2);
4026
		$columnString = PHPExcel_Cell::stringFromColumnIndex($col);
4027
4028
		// Read cell?
4029 View Code Duplication
		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
4030
			// offset: 4; size: 2; XF index
4031
			$xfIndex = self::_GetInt2d($recordData, 4);
4032
4033
			// add style information
4034
			if (!$this->_readDataOnly) {
4035
				$this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
4036
			}
4037
		}
4038
4039
	}
4040
4041
4042
	/**
4043
	 * Read MSODRAWING record
4044
	 */
4045 View Code Duplication
	private function _readMsoDrawing()
4046
	{
4047
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4048
4049
		// get spliced record data
4050
		$splicedRecordData = $this->_getSplicedRecordData();
4051
		$recordData = $splicedRecordData['recordData'];
4052
4053
		$this->_drawingData .= $recordData;
4054
	}
4055
4056
4057
	/**
4058
	 * Read OBJ record
4059
	 */
4060
	private function _readObj()
4061
	{
4062
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4063
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4064
4065
		// move stream pointer to next record
4066
		$this->_pos += 4 + $length;
4067
4068
		if ($this->_readDataOnly || $this->_version != self::XLS_BIFF8) {
4069
			return;
4070
		}
4071
4072
		// recordData consists of an array of subrecords looking like this:
4073
		//	ft: 2 bytes; ftCmo type (0x15)
4074
		//	cb: 2 bytes; size in bytes of ftCmo data
4075
		//	ot: 2 bytes; Object Type
4076
		//	id: 2 bytes; Object id number
4077
		//	grbit: 2 bytes; Option Flags
4078
		//	data: var; subrecord data
4079
4080
		// for now, we are just interested in the second subrecord containing the object type
4081
		$ftCmoType	= self::_GetInt2d($recordData, 0);
4082
		$cbCmoSize	= self::_GetInt2d($recordData, 2);
4083
		$otObjType	= self::_GetInt2d($recordData, 4);
4084
		$idObjID	= self::_GetInt2d($recordData, 6);
4085
		$grbitOpts	= self::_GetInt2d($recordData, 6);
4086
4087
		$this->_objs[] = array(
4088
			'ftCmoType'	=> $ftCmoType,
4089
			'cbCmoSize'	=> $cbCmoSize,
4090
			'otObjType'	=> $otObjType,
4091
			'idObjID'	=> $idObjID,
4092
			'grbitOpts'	=> $grbitOpts
4093
		);
4094
		$this->textObjRef = $idObjID;
4095
4096
//		echo '<b>_readObj()</b><br />';
4097
//		var_dump(end($this->_objs));
4098
//		echo '<br />';
4099
	}
4100
4101
4102
	/**
4103
	 * Read WINDOW2 record
4104
	 */
4105
	private function _readWindow2()
4106
	{
4107
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4108
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4109
4110
		// move stream pointer to next record
4111
		$this->_pos += 4 + $length;
4112
4113
		// offset: 0; size: 2; option flags
4114
		$options = self::_GetInt2d($recordData, 0);
4115
4116
		// bit: 1; mask: 0x0002; 0 = do not show gridlines, 1 = show gridlines
4117
		$showGridlines = (bool) ((0x0002 & $options) >> 1);
4118
		$this->_phpSheet->setShowGridlines($showGridlines);
4119
4120
		// bit: 2; mask: 0x0004; 0 = do not show headers, 1 = show headers
4121
		$showRowColHeaders = (bool) ((0x0004 & $options) >> 2);
4122
		$this->_phpSheet->setShowRowColHeaders($showRowColHeaders);
4123
4124
		// bit: 3; mask: 0x0008; 0 = panes are not frozen, 1 = panes are frozen
4125
		$this->_frozen = (bool) ((0x0008 & $options) >> 3);
4126
4127
		// bit: 6; mask: 0x0040; 0 = columns from left to right, 1 = columns from right to left
4128
		$this->_phpSheet->setRightToLeft((bool)((0x0040 & $options) >> 6));
4129
4130
		// bit: 10; mask: 0x0400; 0 = sheet not active, 1 = sheet active
4131
		$isActive = (bool) ((0x0400 & $options) >> 10);
4132
		if ($isActive) {
4133
			$this->_phpExcel->setActiveSheetIndex($this->_phpExcel->getIndex($this->_phpSheet));
4134
		}
4135
	}
4136
4137
4138
	/**
4139
	 * Read SCL record
4140
	 */
4141
	private function _readScl()
4142
	{
4143
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4144
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4145
4146
		// move stream pointer to next record
4147
		$this->_pos += 4 + $length;
4148
4149
		// offset: 0; size: 2; numerator of the view magnification
4150
		$numerator = self::_GetInt2d($recordData, 0);
4151
4152
		// offset: 2; size: 2; numerator of the view magnification
4153
		$denumerator = self::_GetInt2d($recordData, 2);
4154
4155
		// set the zoom scale (in percent)
4156
		$this->_phpSheet->getSheetView()->setZoomScale($numerator * 100 / $denumerator);
4157
	}
4158
4159
4160
	/**
4161
	 * Read PANE record
4162
	 */
4163
	private function _readPane()
4164
	{
4165
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4166
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4167
4168
		// move stream pointer to next record
4169
		$this->_pos += 4 + $length;
4170
4171
		if (!$this->_readDataOnly) {
4172
			// offset: 0; size: 2; position of vertical split
4173
			$px = self::_GetInt2d($recordData, 0);
4174
4175
			// offset: 2; size: 2; position of horizontal split
4176
			$py = self::_GetInt2d($recordData, 2);
4177
4178
			if ($this->_frozen) {
4179
				// frozen panes
4180
				$this->_phpSheet->freezePane(PHPExcel_Cell::stringFromColumnIndex($px) . ($py + 1));
4181
			} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
4182
				// unfrozen panes; split windows; not supported by PHPExcel core
4183
			}
4184
		}
4185
	}
4186
4187
4188
	/**
4189
	 * Read SELECTION record. There is one such record for each pane in the sheet.
4190
	 */
4191
	private function _readSelection()
4192
	{
4193
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4194
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4195
4196
		// move stream pointer to next record
4197
		$this->_pos += 4 + $length;
4198
4199
		if (!$this->_readDataOnly) {
4200
			// offset: 0; size: 1; pane identifier
4201
			$paneId = ord($recordData{0});
4202
4203
			// offset: 1; size: 2; index to row of the active cell
4204
			$r = self::_GetInt2d($recordData, 1);
4205
4206
			// offset: 3; size: 2; index to column of the active cell
4207
			$c = self::_GetInt2d($recordData, 3);
4208
4209
			// offset: 5; size: 2; index into the following cell range list to the
4210
			//  entry that contains the active cell
4211
			$index = self::_GetInt2d($recordData, 5);
4212
4213
			// offset: 7; size: var; cell range address list containing all selected cell ranges
4214
			$data = substr($recordData, 7);
4215
			$cellRangeAddressList = $this->_readBIFF5CellRangeAddressList($data); // note: also BIFF8 uses BIFF5 syntax
4216
4217
			$selectedCells = $cellRangeAddressList['cellRangeAddresses'][0];
4218
4219
			// first row '1' + last row '16384' indicates that full column is selected (apparently also in BIFF8!)
4220
			if (preg_match('/^([A-Z]+1\:[A-Z]+)16384$/', $selectedCells)) {
4221
				$selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)16384$/', '${1}1048576', $selectedCells);
4222
			}
4223
4224
			// first row '1' + last row '65536' indicates that full column is selected
4225
			if (preg_match('/^([A-Z]+1\:[A-Z]+)65536$/', $selectedCells)) {
4226
				$selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)65536$/', '${1}1048576', $selectedCells);
4227
			}
4228
4229
			// first column 'A' + last column 'IV' indicates that full row is selected
4230
			if (preg_match('/^(A[0-9]+\:)IV([0-9]+)$/', $selectedCells)) {
4231
				$selectedCells = preg_replace('/^(A[0-9]+\:)IV([0-9]+)$/', '${1}XFD${2}', $selectedCells);
4232
			}
4233
4234
			$this->_phpSheet->setSelectedCells($selectedCells);
4235
		}
4236
	}
4237
4238
4239
	private function _includeCellRangeFiltered($cellRangeAddress)
4240
	{
4241
		$includeCellRange = true;
4242
		if ($this->getReadFilter() !== NULL) {
4243
			$includeCellRange = false;
4244
			$rangeBoundaries = PHPExcel_Cell::getRangeBoundaries($cellRangeAddress);
4245
			$rangeBoundaries[1][0]++;
4246
			for ($row = $rangeBoundaries[0][1]; $row <= $rangeBoundaries[1][1]; $row++) {
4247
				for ($column = $rangeBoundaries[0][0]; $column != $rangeBoundaries[1][0]; $column++) {
4248
					if ($this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle())) {
4249
						$includeCellRange = true;
4250
						break 2;
4251
					}
4252
				}
4253
			}
4254
		}
4255
		return $includeCellRange;
4256
	}
4257
4258
4259
	/**
4260
	 * MERGEDCELLS
4261
	 *
4262
	 * This record contains the addresses of merged cell ranges
4263
	 * in the current sheet.
4264
	 *
4265
	 * --	"OpenOffice.org's Documentation of the Microsoft
4266
	 * 		Excel File Format"
4267
	 */
4268
	private function _readMergedCells()
4269
	{
4270
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4271
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4272
4273
		// move stream pointer to next record
4274
		$this->_pos += 4 + $length;
4275
4276
		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
4277
			$cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($recordData);
4278
			foreach ($cellRangeAddressList['cellRangeAddresses'] as $cellRangeAddress) {
4279
				if ($this->_includeCellRangeFiltered($cellRangeAddress)) {
4280
					$this->_phpSheet->mergeCells($cellRangeAddress);
4281
				}
4282
			}
4283
		}
4284
	}
4285
4286
4287
	/**
4288
	 * Read HYPERLINK record
4289
	 */
4290
	private function _readHyperLink()
4291
	{
4292
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4293
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4294
4295
		// move stream pointer forward to next record
4296
		$this->_pos += 4 + $length;
4297
4298
		if (!$this->_readDataOnly) {
4299
			// offset: 0; size: 8; cell range address of all cells containing this hyperlink
4300
			try {
4301
				$cellRange = $this->_readBIFF8CellRangeAddressFixed($recordData, 0, 8);
4302
			} catch (Exception $e) {
4303
				return;
4304
			}
4305
4306
			// offset: 8, size: 16; GUID of StdLink
4307
4308
			// offset: 24, size: 4; unknown value
4309
4310
			// offset: 28, size: 4; option flags
4311
4312
				// bit: 0; mask: 0x00000001; 0 = no link or extant, 1 = file link or URL
4313
				$isFileLinkOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 0;
4314
4315
				// bit: 1; mask: 0x00000002; 0 = relative path, 1 = absolute path or URL
4316
				$isAbsPathOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 1;
4317
4318
				// bit: 2 (and 4); mask: 0x00000014; 0 = no description
4319
				$hasDesc = (0x00000014 & self::_GetInt2d($recordData, 28)) >> 2;
4320
4321
				// bit: 3; mask: 0x00000008; 0 = no text, 1 = has text
4322
				$hasText = (0x00000008 & self::_GetInt2d($recordData, 28)) >> 3;
4323
4324
				// bit: 7; mask: 0x00000080; 0 = no target frame, 1 = has target frame
4325
				$hasFrame = (0x00000080 & self::_GetInt2d($recordData, 28)) >> 7;
4326
4327
				// bit: 8; mask: 0x00000100; 0 = file link or URL, 1 = UNC path (inc. server name)
4328
				$isUNC = (0x00000100 & self::_GetInt2d($recordData, 28)) >> 8;
4329
4330
			// offset within record data
4331
			$offset = 32;
4332
4333
			if ($hasDesc) {
4334
				// offset: 32; size: var; character count of description text
4335
				$dl = self::_GetInt4d($recordData, 32);
4336
				// offset: 36; size: var; character array of description text, no Unicode string header, always 16-bit characters, zero terminated
4337
				$desc = self::_encodeUTF16(substr($recordData, 36, 2 * ($dl - 1)), false);
4338
				$offset += 4 + 2 * $dl;
4339
			}
4340
			if ($hasFrame) {
4341
				$fl = self::_GetInt4d($recordData, $offset);
4342
				$offset += 4 + 2 * $fl;
4343
			}
4344
4345
			// detect type of hyperlink (there are 4 types)
4346
			$hyperlinkType = null;
4347
4348
			if ($isUNC) {
4349
				$hyperlinkType = 'UNC';
4350
			} else if (!$isFileLinkOrUrl) {
4351
				$hyperlinkType = 'workbook';
4352
			} else if (ord($recordData{$offset}) == 0x03) {
4353
				$hyperlinkType = 'local';
4354
			} else if (ord($recordData{$offset}) == 0xE0) {
4355
				$hyperlinkType = 'URL';
4356
			}
4357
4358
			switch ($hyperlinkType) {
4359
			case 'URL':
4360
				// section 5.58.2: Hyperlink containing a URL
4361
				// e.g. http://example.org/index.php
4362
4363
				// offset: var; size: 16; GUID of URL Moniker
4364
				$offset += 16;
4365
				// offset: var; size: 4; size (in bytes) of character array of the URL including trailing zero word
4366
				$us = self::_GetInt4d($recordData, $offset);
4367
				$offset += 4;
4368
				// offset: var; size: $us; character array of the URL, no Unicode string header, always 16-bit characters, zero-terminated
4369
				$url = self::_encodeUTF16(substr($recordData, $offset, $us - 2), false);
4370
				$url .= $hasText ? '#' : '';
4371
				$offset += $us;
4372
				break;
4373
4374
			case 'local':
4375
				// section 5.58.3: Hyperlink to local file
4376
				// examples:
4377
				//   mydoc.txt
4378
				//   ../../somedoc.xls#Sheet!A1
4379
4380
				// offset: var; size: 16; GUI of File Moniker
4381
				$offset += 16;
4382
4383
				// offset: var; size: 2; directory up-level count.
4384
				$upLevelCount = self::_GetInt2d($recordData, $offset);
4385
				$offset += 2;
4386
4387
				// offset: var; size: 4; character count of the shortened file path and name, including trailing zero word
4388
				$sl = self::_GetInt4d($recordData, $offset);
4389
				$offset += 4;
4390
4391
				// offset: var; size: sl; character array of the shortened file path and name in 8.3-DOS-format (compressed Unicode string)
4392
				$shortenedFilePath = substr($recordData, $offset, $sl);
4393
				$shortenedFilePath = self::_encodeUTF16($shortenedFilePath, true);
4394
				$shortenedFilePath = substr($shortenedFilePath, 0, -1); // remove trailing zero
4395
4396
				$offset += $sl;
4397
4398
				// offset: var; size: 24; unknown sequence
4399
				$offset += 24;
4400
4401
				// extended file path
4402
				// offset: var; size: 4; size of the following file link field including string lenth mark
4403
				$sz = self::_GetInt4d($recordData, $offset);
4404
				$offset += 4;
4405
4406
				// only present if $sz > 0
4407
				if ($sz > 0) {
4408
					// offset: var; size: 4; size of the character array of the extended file path and name
4409
					$xl = self::_GetInt4d($recordData, $offset);
4410
					$offset += 4;
4411
4412
					// offset: var; size 2; unknown
4413
					$offset += 2;
4414
4415
					// offset: var; size $xl; character array of the extended file path and name.
4416
					$extendedFilePath = substr($recordData, $offset, $xl);
4417
					$extendedFilePath = self::_encodeUTF16($extendedFilePath, false);
4418
					$offset += $xl;
4419
				}
4420
4421
				// construct the path
4422
				$url = str_repeat('..\\', $upLevelCount);
4423
				$url .= ($sz > 0) ?
4424
					$extendedFilePath : $shortenedFilePath; // use extended path if available
0 ignored issues
show
Bug introduced by
The variable $extendedFilePath does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
4425
				$url .= $hasText ? '#' : '';
4426
4427
				break;
4428
4429
4430
			case 'UNC':
4431
				// section 5.58.4: Hyperlink to a File with UNC (Universal Naming Convention) Path
4432
				// todo: implement
4433
				return;
4434
4435
			case 'workbook':
4436
				// section 5.58.5: Hyperlink to the Current Workbook
4437
				// e.g. Sheet2!B1:C2, stored in text mark field
4438
				$url = 'sheet://';
4439
				break;
4440
4441
			default:
4442
				return;
4443
4444
			}
4445
4446
			if ($hasText) {
4447
				// offset: var; size: 4; character count of text mark including trailing zero word
4448
				$tl = self::_GetInt4d($recordData, $offset);
4449
				$offset += 4;
4450
				// offset: var; size: var; character array of the text mark without the # sign, no Unicode header, always 16-bit characters, zero-terminated
4451
				$text = self::_encodeUTF16(substr($recordData, $offset, 2 * ($tl - 1)), false);
4452
				$url .= $text;
4453
			}
4454
4455
			// apply the hyperlink to all the relevant cells
4456
			foreach (PHPExcel_Cell::extractAllCellReferencesInRange($cellRange) as $coordinate) {
4457
				$this->_phpSheet->getCell($coordinate)->getHyperLink()->setUrl($url);
4458
			}
4459
		}
4460
	}
4461
4462
4463
	/**
4464
	 * Read DATAVALIDATIONS record
4465
	 */
4466 View Code Duplication
	private function _readDataValidations()
4467
	{
4468
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4469
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4470
4471
		// move stream pointer forward to next record
4472
		$this->_pos += 4 + $length;
4473
	}
4474
4475
4476
	/**
4477
	 * Read DATAVALIDATION record
4478
	 */
4479
	private function _readDataValidation()
4480
	{
4481
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4482
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4483
4484
		// move stream pointer forward to next record
4485
		$this->_pos += 4 + $length;
4486
4487
		if ($this->_readDataOnly) {
4488
			return;
4489
		}
4490
4491
		// offset: 0; size: 4; Options
4492
		$options = self::_GetInt4d($recordData, 0);
4493
4494
		// bit: 0-3; mask: 0x0000000F; type
4495
		$type = (0x0000000F & $options) >> 0;
4496 View Code Duplication
		switch ($type) {
4497
			case 0x00:	$type = PHPExcel_Cell_DataValidation::TYPE_NONE;		break;
4498
			case 0x01:	$type = PHPExcel_Cell_DataValidation::TYPE_WHOLE;		break;
4499
			case 0x02:	$type = PHPExcel_Cell_DataValidation::TYPE_DECIMAL;		break;
4500
			case 0x03:	$type = PHPExcel_Cell_DataValidation::TYPE_LIST;		break;
4501
			case 0x04:	$type = PHPExcel_Cell_DataValidation::TYPE_DATE;		break;
4502
			case 0x05:	$type = PHPExcel_Cell_DataValidation::TYPE_TIME;		break;
4503
			case 0x06:	$type = PHPExcel_Cell_DataValidation::TYPE_TEXTLENGTH;	break;
4504
			case 0x07:	$type = PHPExcel_Cell_DataValidation::TYPE_CUSTOM;		break;
4505
		}
4506
4507
		// bit: 4-6; mask: 0x00000070; error type
4508
		$errorStyle = (0x00000070 & $options) >> 4;
4509 View Code Duplication
		switch ($errorStyle) {
4510
			case 0x00:	$errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP;			break;
4511
			case 0x01:	$errorStyle = PHPExcel_Cell_DataValidation::STYLE_WARNING;		break;
4512
			case 0x02:	$errorStyle = PHPExcel_Cell_DataValidation::STYLE_INFORMATION;	break;
4513
		}
4514
4515
		// bit: 7; mask: 0x00000080; 1= formula is explicit (only applies to list)
4516
		// I have only seen cases where this is 1
4517
		$explicitFormula = (0x00000080 & $options) >> 7;
4518
4519
		// bit: 8; mask: 0x00000100; 1= empty cells allowed
4520
		$allowBlank = (0x00000100 & $options) >> 8;
4521
4522
		// bit: 9; mask: 0x00000200; 1= suppress drop down arrow in list type validity
4523
		$suppressDropDown = (0x00000200 & $options) >> 9;
4524
4525
		// bit: 18; mask: 0x00040000; 1= show prompt box if cell selected
4526
		$showInputMessage = (0x00040000 & $options) >> 18;
4527
4528
		// bit: 19; mask: 0x00080000; 1= show error box if invalid values entered
4529
		$showErrorMessage = (0x00080000 & $options) >> 19;
4530
4531
		// bit: 20-23; mask: 0x00F00000; condition operator
4532
		$operator = (0x00F00000 & $options) >> 20;
4533 View Code Duplication
		switch ($operator) {
4534
			case 0x00: $operator = PHPExcel_Cell_DataValidation::OPERATOR_BETWEEN			;	break;
4535
			case 0x01: $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTBETWEEN		;	break;
4536
			case 0x02: $operator = PHPExcel_Cell_DataValidation::OPERATOR_EQUAL				;	break;
4537
			case 0x03: $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTEQUAL			;	break;
4538
			case 0x04: $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHAN		;	break;
4539
			case 0x05: $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHAN			;	break;
4540
			case 0x06: $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHANOREQUAL;	break;
4541
			case 0x07: $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHANOREQUAL	;	break;
4542
		}
4543
4544
		// offset: 4; size: var; title of the prompt box
4545
		$offset = 4;
4546
		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
4547
		$promptTitle = $string['value'] !== chr(0) ?
4548
			$string['value'] : '';
4549
		$offset += $string['size'];
4550
4551
		// offset: var; size: var; title of the error box
4552
		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
4553
		$errorTitle = $string['value'] !== chr(0) ?
4554
			$string['value'] : '';
4555
		$offset += $string['size'];
4556
4557
		// offset: var; size: var; text of the prompt box
4558
		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
4559
		$prompt = $string['value'] !== chr(0) ?
4560
			$string['value'] : '';
4561
		$offset += $string['size'];
4562
4563
		// offset: var; size: var; text of the error box
4564
		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
4565
		$error = $string['value'] !== chr(0) ?
4566
			$string['value'] : '';
4567
		$offset += $string['size'];
4568
4569
		// offset: var; size: 2; size of the formula data for the first condition
4570
		$sz1 = self::_GetInt2d($recordData, $offset);
4571
		$offset += 2;
4572
4573
		// offset: var; size: 2; not used
4574
		$offset += 2;
4575
4576
		// offset: var; size: $sz1; formula data for first condition (without size field)
4577
		$formula1 = substr($recordData, $offset, $sz1);
4578
		$formula1 = pack('v', $sz1) . $formula1; // prepend the length
4579
		try {
4580
			$formula1 = $this->_getFormulaFromStructure($formula1);
4581
4582
			// in list type validity, null characters are used as item separators
4583
			if ($type == PHPExcel_Cell_DataValidation::TYPE_LIST) {
4584
				$formula1 = str_replace(chr(0), ',', $formula1);
4585
			}
4586
		} catch (Exception $e) {
4587
			return;
4588
		}
4589
		$offset += $sz1;
4590
4591
		// offset: var; size: 2; size of the formula data for the first condition
4592
		$sz2 = self::_GetInt2d($recordData, $offset);
4593
		$offset += 2;
4594
4595
		// offset: var; size: 2; not used
4596
		$offset += 2;
4597
4598
		// offset: var; size: $sz2; formula data for second condition (without size field)
4599
		$formula2 = substr($recordData, $offset, $sz2);
4600
		$formula2 = pack('v', $sz2) . $formula2; // prepend the length
4601
		try {
4602
			$formula2 = $this->_getFormulaFromStructure($formula2);
4603
		} catch (Exception $e) {
4604
			return;
4605
		}
4606
		$offset += $sz2;
4607
4608
		// offset: var; size: var; cell range address list with
4609
		$cellRangeAddressList = $this->_readBIFF8CellRangeAddressList(substr($recordData, $offset));
4610
		$cellRangeAddresses = $cellRangeAddressList['cellRangeAddresses'];
4611
4612
		foreach ($cellRangeAddresses as $cellRange) {
4613
			$stRange = $this->_phpSheet->shrinkRangeToFit($cellRange);
4614
			$stRange = PHPExcel_Cell::extractAllCellReferencesInRange($stRange);
4615
			foreach ($stRange as $coordinate) {
4616
				$objValidation = $this->_phpSheet->getCell($coordinate)->getDataValidation();
4617
				$objValidation->setType($type);
4618
				$objValidation->setErrorStyle($errorStyle);
4619
				$objValidation->setAllowBlank((bool)$allowBlank);
4620
				$objValidation->setShowInputMessage((bool)$showInputMessage);
4621
				$objValidation->setShowErrorMessage((bool)$showErrorMessage);
4622
				$objValidation->setShowDropDown(!$suppressDropDown);
4623
				$objValidation->setOperator($operator);
4624
				$objValidation->setErrorTitle($errorTitle);
4625
				$objValidation->setError($error);
4626
				$objValidation->setPromptTitle($promptTitle);
4627
				$objValidation->setPrompt($prompt);
4628
				$objValidation->setFormula1($formula1);
4629
				$objValidation->setFormula2($formula2);
4630
			}
4631
		}
4632
4633
	}
4634
4635
4636
	/**
4637
	 * Read SHEETLAYOUT record. Stores sheet tab color information.
4638
	 */
4639
	private function _readSheetLayout()
4640
	{
4641
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4642
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4643
4644
		// move stream pointer to next record
4645
		$this->_pos += 4 + $length;
4646
4647
		// local pointer in record data
4648
		$offset = 0;
4649
4650
		if (!$this->_readDataOnly) {
4651
			// offset: 0; size: 2; repeated record identifier 0x0862
4652
4653
			// offset: 2; size: 10; not used
4654
4655
			// offset: 12; size: 4; size of record data
4656
			// Excel 2003 uses size of 0x14 (documented), Excel 2007 uses size of 0x28 (not documented?)
4657
			$sz = self::_GetInt4d($recordData, 12);
4658
4659
			switch ($sz) {
4660
				case 0x14:
4661
					// offset: 16; size: 2; color index for sheet tab
4662
					$colorIndex = self::_GetInt2d($recordData, 16);
4663
					$color = self::_readColor($colorIndex,$this->_palette,$this->_version);
4664
					$this->_phpSheet->getTabColor()->setRGB($color['rgb']);
4665
					break;
4666
4667
				case 0x28:
4668
					// TODO: Investigate structure for .xls SHEETLAYOUT record as saved by MS Office Excel 2007
4669
					return;
4670
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
4671
			}
4672
		}
4673
	}
4674
4675
4676
	/**
4677
	 * Read SHEETPROTECTION record (FEATHEADR)
4678
	 */
4679
	private function _readSheetProtection()
4680
	{
4681
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4682
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4683
4684
		// move stream pointer to next record
4685
		$this->_pos += 4 + $length;
4686
4687
		if ($this->_readDataOnly) {
4688
			return;
4689
		}
4690
4691
		// offset: 0; size: 2; repeated record header
4692
4693
		// offset: 2; size: 2; FRT cell reference flag (=0 currently)
4694
4695
		// offset: 4; size: 8; Currently not used and set to 0
4696
4697
		// offset: 12; size: 2; Shared feature type index (2=Enhanced Protetion, 4=SmartTag)
4698
		$isf = self::_GetInt2d($recordData, 12);
4699
		if ($isf != 2) {
4700
			return;
4701
		}
4702
4703
		// offset: 14; size: 1; =1 since this is a feat header
4704
4705
		// offset: 15; size: 4; size of rgbHdrSData
4706
4707
		// rgbHdrSData, assume "Enhanced Protection"
4708
		// offset: 19; size: 2; option flags
4709
		$options = self::_GetInt2d($recordData, 19);
4710
4711
		// bit: 0; mask 0x0001; 1 = user may edit objects, 0 = users must not edit objects
4712
		$bool = (0x0001 & $options) >> 0;
4713
		$this->_phpSheet->getProtection()->setObjects(!$bool);
4714
4715
		// bit: 1; mask 0x0002; edit scenarios
4716
		$bool = (0x0002 & $options) >> 1;
4717
		$this->_phpSheet->getProtection()->setScenarios(!$bool);
4718
4719
		// bit: 2; mask 0x0004; format cells
4720
		$bool = (0x0004 & $options) >> 2;
4721
		$this->_phpSheet->getProtection()->setFormatCells(!$bool);
4722
4723
		// bit: 3; mask 0x0008; format columns
4724
		$bool = (0x0008 & $options) >> 3;
4725
		$this->_phpSheet->getProtection()->setFormatColumns(!$bool);
4726
4727
		// bit: 4; mask 0x0010; format rows
4728
		$bool = (0x0010 & $options) >> 4;
4729
		$this->_phpSheet->getProtection()->setFormatRows(!$bool);
4730
4731
		// bit: 5; mask 0x0020; insert columns
4732
		$bool = (0x0020 & $options) >> 5;
4733
		$this->_phpSheet->getProtection()->setInsertColumns(!$bool);
4734
4735
		// bit: 6; mask 0x0040; insert rows
4736
		$bool = (0x0040 & $options) >> 6;
4737
		$this->_phpSheet->getProtection()->setInsertRows(!$bool);
4738
4739
		// bit: 7; mask 0x0080; insert hyperlinks
4740
		$bool = (0x0080 & $options) >> 7;
4741
		$this->_phpSheet->getProtection()->setInsertHyperlinks(!$bool);
4742
4743
		// bit: 8; mask 0x0100; delete columns
4744
		$bool = (0x0100 & $options) >> 8;
4745
		$this->_phpSheet->getProtection()->setDeleteColumns(!$bool);
4746
4747
		// bit: 9; mask 0x0200; delete rows
4748
		$bool = (0x0200 & $options) >> 9;
4749
		$this->_phpSheet->getProtection()->setDeleteRows(!$bool);
4750
4751
		// bit: 10; mask 0x0400; select locked cells
4752
		$bool = (0x0400 & $options) >> 10;
4753
		$this->_phpSheet->getProtection()->setSelectLockedCells(!$bool);
4754
4755
		// bit: 11; mask 0x0800; sort cell range
4756
		$bool = (0x0800 & $options) >> 11;
4757
		$this->_phpSheet->getProtection()->setSort(!$bool);
4758
4759
		// bit: 12; mask 0x1000; auto filter
4760
		$bool = (0x1000 & $options) >> 12;
4761
		$this->_phpSheet->getProtection()->setAutoFilter(!$bool);
4762
4763
		// bit: 13; mask 0x2000; pivot tables
4764
		$bool = (0x2000 & $options) >> 13;
4765
		$this->_phpSheet->getProtection()->setPivotTables(!$bool);
4766
4767
		// bit: 14; mask 0x4000; select unlocked cells
4768
		$bool = (0x4000 & $options) >> 14;
4769
		$this->_phpSheet->getProtection()->setSelectUnlockedCells(!$bool);
4770
4771
		// offset: 21; size: 2; not used
4772
	}
4773
4774
4775
	/**
4776
	 * Read RANGEPROTECTION record
4777
	 * Reading of this record is based on Microsoft Office Excel 97-2000 Binary File Format Specification,
4778
	 * where it is referred to as FEAT record
4779
	 */
4780
	private function _readRangeProtection()
4781
	{
4782
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4783
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4784
4785
		// move stream pointer to next record
4786
		$this->_pos += 4 + $length;
4787
4788
		// local pointer in record data
4789
		$offset = 0;
4790
4791
		if (!$this->_readDataOnly) {
4792
			$offset += 12;
4793
4794
			// offset: 12; size: 2; shared feature type, 2 = enhanced protection, 4 = smart tag
4795
			$isf = self::_GetInt2d($recordData, 12);
4796
			if ($isf != 2) {
4797
				// we only read FEAT records of type 2
4798
				return;
4799
			}
4800
			$offset += 2;
4801
4802
			$offset += 5;
4803
4804
			// offset: 19; size: 2; count of ref ranges this feature is on
4805
			$cref = self::_GetInt2d($recordData, 19);
4806
			$offset += 2;
4807
4808
			$offset += 6;
4809
4810
			// offset: 27; size: 8 * $cref; list of cell ranges (like in hyperlink record)
4811
			$cellRanges = array();
4812
			for ($i = 0; $i < $cref; ++$i) {
4813
				try {
4814
					$cellRange = $this->_readBIFF8CellRangeAddressFixed(substr($recordData, 27 + 8 * $i, 8));
4815
				} catch (Exception $e) {
4816
					return;
4817
				}
4818
				$cellRanges[] = $cellRange;
4819
				$offset += 8;
4820
			}
4821
4822
			// offset: var; size: var; variable length of feature specific data
4823
			$rgbFeat = substr($recordData, $offset);
4824
			$offset += 4;
4825
4826
			// offset: var; size: 4; the encrypted password (only 16-bit although field is 32-bit)
4827
			$wPassword = self::_GetInt4d($recordData, $offset);
4828
			$offset += 4;
4829
4830
			// Apply range protection to sheet
4831
			if ($cellRanges) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cellRanges of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
4832
				$this->_phpSheet->protectCells(implode(' ', $cellRanges), strtoupper(dechex($wPassword)), true);
4833
			}
4834
		}
4835
	}
4836
4837
4838
	/**
4839
	 * Read IMDATA record
4840
	 */
4841
	private function _readImData()
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
4842
	{
4843
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4844
4845
		// get spliced record data
4846
		$splicedRecordData = $this->_getSplicedRecordData();
4847
		$recordData = $splicedRecordData['recordData'];
4848
4849
		// UNDER CONSTRUCTION
4850
4851
		// offset: 0; size: 2; image format
4852
		$cf = self::_GetInt2d($recordData, 0);
4853
4854
		// offset: 2; size: 2; environment from which the file was written
4855
		$env = self::_GetInt2d($recordData, 2);
4856
4857
		// offset: 4; size: 4; length of the image data
4858
		$lcb = self::_GetInt4d($recordData, 4);
4859
4860
		// offset: 8; size: var; image data
4861
		$iData = substr($recordData, 8);
4862
4863
		switch ($cf) {
4864
		case 0x09: // Windows bitmap format
4865
			// BITMAPCOREINFO
4866
			// 1. BITMAPCOREHEADER
4867
			// offset: 0; size: 4; bcSize, Specifies the number of bytes required by the structure
4868
			$bcSize = self::_GetInt4d($iData, 0);
4869
//			var_dump($bcSize);
4870
4871
			// offset: 4; size: 2; bcWidth, specifies the width of the bitmap, in pixels
4872
			$bcWidth = self::_GetInt2d($iData, 4);
4873
//			var_dump($bcWidth);
4874
4875
			// offset: 6; size: 2; bcHeight, specifies the height of the bitmap, in pixels.
4876
			$bcHeight = self::_GetInt2d($iData, 6);
4877
//			var_dump($bcHeight);
4878
			$ih = imagecreatetruecolor($bcWidth, $bcHeight);
4879
4880
			// offset: 8; size: 2; bcPlanes, specifies the number of planes for the target device. This value must be 1
4881
4882
			// offset: 10; size: 2; bcBitCount specifies the number of bits-per-pixel. This value must be 1, 4, 8, or 24
4883
			$bcBitCount = self::_GetInt2d($iData, 10);
4884
//			var_dump($bcBitCount);
4885
4886
			$rgbString = substr($iData, 12);
4887
			$rgbTriples = array();
4888
			while (strlen($rgbString) > 0) {
4889
				$rgbTriples[] = unpack('Cb/Cg/Cr', $rgbString);
4890
				$rgbString = substr($rgbString, 3);
4891
			}
4892
			$x = 0;
4893
			$y = 0;
4894
			foreach ($rgbTriples as $i => $rgbTriple) {
4895
				$color = imagecolorallocate($ih, $rgbTriple['r'], $rgbTriple['g'], $rgbTriple['b']);
4896
				imagesetpixel($ih, $x, $bcHeight - 1 - $y, $color);
4897
				$x = ($x + 1) % $bcWidth;
4898
				$y = $y + floor(($x + 1) / $bcWidth);
4899
			}
4900
			//imagepng($ih, 'image.png');
4901
4902
			$drawing = new PHPExcel_Worksheet_Drawing();
4903
			$drawing->setPath($filename);
0 ignored issues
show
Bug introduced by
The variable $filename does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
4904
			$drawing->setWorksheet($this->_phpSheet);
4905
4906
			break;
4907
4908
		case 0x02: // Windows metafile or Macintosh PICT format
4909
		case 0x0e: // native format
4910
		default;
0 ignored issues
show
Coding Style introduced by
DEFAULT statements must be defined using a colon

As per the PSR-2 coding standard, default statements should not be wrapped in curly braces.

switch ($expr) {
    default: { //wrong
        doSomething();
        break;
    }
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
4911
			break;
4912
4913
		}
4914
4915
		// _getSplicedRecordData() takes care of moving current position in data stream
4916
	}
4917
4918
4919
	/**
4920
	 * Read a free CONTINUE record. Free CONTINUE record may be a camouflaged MSODRAWING record
4921
	 * When MSODRAWING data on a sheet exceeds 8224 bytes, CONTINUE records are used instead. Undocumented.
4922
	 * In this case, we must treat the CONTINUE record as a MSODRAWING record
4923
	 */
4924
	private function _readContinue()
4925
	{
4926
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4927
		$recordData = substr($this->_data, $this->_pos + 4, $length);
4928
4929
		// check if we are reading drawing data
4930
		// this is in case a free CONTINUE record occurs in other circumstances we are unaware of
4931
		if ($this->_drawingData == '') {
4932
			// move stream pointer to next record
4933
			$this->_pos += 4 + $length;
4934
4935
			return;
4936
		}
4937
4938
		// check if record data is at least 4 bytes long, otherwise there is no chance this is MSODRAWING data
4939
		if ($length < 4) {
4940
			// move stream pointer to next record
4941
			$this->_pos += 4 + $length;
4942
4943
			return;
4944
		}
4945
4946
		// dirty check to see if CONTINUE record could be a camouflaged MSODRAWING record
4947
		// look inside CONTINUE record to see if it looks like a part of an Escher stream
4948
		// we know that Escher stream may be split at least at
4949
		//		0xF003 MsofbtSpgrContainer
4950
		//		0xF004 MsofbtSpContainer
4951
		//		0xF00D MsofbtClientTextbox
4952
		$validSplitPoints = array(0xF003, 0xF004, 0xF00D); // add identifiers if we find more
4953
4954
		$splitPoint = self::_GetInt2d($recordData, 2);
4955
		if (in_array($splitPoint, $validSplitPoints)) {
4956
			// get spliced record data (and move pointer to next record)
4957
			$splicedRecordData = $this->_getSplicedRecordData();
4958
			$this->_drawingData .= $splicedRecordData['recordData'];
4959
4960
			return;
4961
		}
4962
4963
		// move stream pointer to next record
4964
		$this->_pos += 4 + $length;
4965
4966
	}
4967
4968
4969
	/**
4970
	 * Reads a record from current position in data stream and continues reading data as long as CONTINUE
4971
	 * records are found. Splices the record data pieces and returns the combined string as if record data
4972
	 * is in one piece.
4973
	 * Moves to next current position in data stream to start of next record different from a CONtINUE record
4974
	 *
4975
	 * @return array
4976
	 */
4977
	private function _getSplicedRecordData()
4978
	{
4979
		$data = '';
4980
		$spliceOffsets = array();
4981
4982
		$i = 0;
4983
		$spliceOffsets[0] = 0;
4984
4985
		do {
4986
			++$i;
4987
4988
			// offset: 0; size: 2; identifier
4989
			$identifier = self::_GetInt2d($this->_data, $this->_pos);
4990
			// offset: 2; size: 2; length
4991
			$length = self::_GetInt2d($this->_data, $this->_pos + 2);
4992
			$data .= substr($this->_data, $this->_pos + 4, $length);
4993
4994
			$spliceOffsets[$i] = $spliceOffsets[$i - 1] + $length;
4995
4996
			$this->_pos += 4 + $length;
4997
			$nextIdentifier = self::_GetInt2d($this->_data, $this->_pos);
4998
		}
4999
		while ($nextIdentifier == self::XLS_Type_CONTINUE);
5000
5001
		$splicedData = array(
5002
			'recordData' => $data,
5003
			'spliceOffsets' => $spliceOffsets,
5004
		);
5005
5006
		return $splicedData;
5007
5008
	}
5009
5010
5011
	/**
5012
	 * Convert formula structure into human readable Excel formula like 'A3+A5*5'
5013
	 *
5014
	 * @param string $formulaStructure The complete binary data for the formula
5015
	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5016
	 * @return string Human readable formula
5017
	 */
5018
	private function _getFormulaFromStructure($formulaStructure, $baseCell = 'A1')
5019
	{
5020
		// offset: 0; size: 2; size of the following formula data
5021
		$sz = self::_GetInt2d($formulaStructure, 0);
5022
5023
		// offset: 2; size: sz
5024
		$formulaData = substr($formulaStructure, 2, $sz);
5025
5026
		// for debug: dump the formula data
5027
		//echo '<xmp>';
5028
		//echo 'size: ' . $sz . "\n";
5029
		//echo 'the entire formula data: ';
5030
		//Debug::dump($formulaData);
5031
		//echo "\n----\n";
5032
5033
		// offset: 2 + sz; size: variable (optional)
5034
		if (strlen($formulaStructure) > 2 + $sz) {
5035
			$additionalData = substr($formulaStructure, 2 + $sz);
5036
5037
			// for debug: dump the additional data
5038
			//echo 'the entire additional data: ';
5039
			//Debug::dump($additionalData);
5040
			//echo "\n----\n";
5041
5042
		} else {
5043
			$additionalData = '';
5044
		}
5045
5046
		return $this->_getFormulaFromData($formulaData, $additionalData, $baseCell);
5047
	}
5048
5049
5050
	/**
5051
	 * Take formula data and additional data for formula and return human readable formula
5052
	 *
5053
	 * @param string $formulaData The binary data for the formula itself
5054
	 * @param string $additionalData Additional binary data going with the formula
5055
	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5056
	 * @return string Human readable formula
5057
	 */
5058
	private function _getFormulaFromData($formulaData,  $additionalData = '', $baseCell = 'A1')
5059
	{
5060
		// start parsing the formula data
5061
		$tokens = array();
5062
5063
		while (strlen($formulaData) > 0 and $token = $this->_getNextToken($formulaData, $baseCell)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
5064
			$tokens[] = $token;
5065
			$formulaData = substr($formulaData, $token['size']);
5066
5067
			// for debug: dump the token
5068
			//var_dump($token);
5069
		}
5070
5071
		$formulaString = $this->_createFormulaFromTokens($tokens, $additionalData);
5072
5073
		return $formulaString;
5074
	}
5075
5076
5077
	/**
5078
	 * Take array of tokens together with additional data for formula and return human readable formula
5079
	 *
5080
	 * @param array $tokens
5081
	 * @param array $additionalData Additional binary data going with the formula
5082
	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
0 ignored issues
show
Bug introduced by
There is no parameter named $baseCell. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
5083
	 * @return string Human readable formula
5084
	 */
5085
	private function _createFormulaFromTokens($tokens, $additionalData)
5086
	{
5087
		// empty formula?
5088
		if (empty($tokens)) {
5089
			return '';
5090
		}
5091
5092
		$formulaStrings = array();
5093
		foreach ($tokens as $token) {
5094
			// initialize spaces
5095
			$space0 = isset($space0) ? $space0 : ''; // spaces before next token, not tParen
5096
			$space1 = isset($space1) ? $space1 : ''; // carriage returns before next token, not tParen
5097
			$space2 = isset($space2) ? $space2 : ''; // spaces before opening parenthesis
5098
			$space3 = isset($space3) ? $space3 : ''; // carriage returns before opening parenthesis
5099
			$space4 = isset($space4) ? $space4 : ''; // spaces before closing parenthesis
5100
			$space5 = isset($space5) ? $space5 : ''; // carriage returns before closing parenthesis
5101
5102
			switch ($token['name']) {
5103
			case 'tAdd': // addition
5104
			case 'tConcat': // addition
5105
			case 'tDiv': // division
5106
			case 'tEQ': // equality
5107
			case 'tGE': // greater than or equal
5108
			case 'tGT': // greater than
5109
			case 'tIsect': // intersection
5110
			case 'tLE': // less than or equal
5111
			case 'tList': // less than or equal
5112
			case 'tLT': // less than
5113
			case 'tMul': // multiplication
5114
			case 'tNE': // multiplication
5115
			case 'tPower': // power
5116
			case 'tRange': // range
5117
			case 'tSub': // subtraction
5118
				$op2 = array_pop($formulaStrings);
5119
				$op1 = array_pop($formulaStrings);
5120
				$formulaStrings[] = "$op1$space1$space0{$token['data']}$op2";
5121
				unset($space0, $space1);
5122
				break;
5123
			case 'tUplus': // unary plus
5124 View Code Duplication
			case 'tUminus': // unary minus
5125
				$op = array_pop($formulaStrings);
5126
				$formulaStrings[] = "$space1$space0{$token['data']}$op";
5127
				unset($space0, $space1);
5128
				break;
5129 View Code Duplication
			case 'tPercent': // percent sign
5130
				$op = array_pop($formulaStrings);
5131
				$formulaStrings[] = "$op$space1$space0{$token['data']}";
5132
				unset($space0, $space1);
5133
				break;
5134
			case 'tAttrVolatile': // indicates volatile function
5135
			case 'tAttrIf':
5136
			case 'tAttrSkip':
5137
			case 'tAttrChoose':
5138
				// token is only important for Excel formula evaluator
5139
				// do nothing
5140
				break;
5141
			case 'tAttrSpace': // space / carriage return
5142
				// space will be used when next token arrives, do not alter formulaString stack
5143
				switch ($token['data']['spacetype']) {
5144
				case 'type0':
5145
					$space0 = str_repeat(' ', $token['data']['spacecount']);
5146
					break;
5147
				case 'type1':
5148
					$space1 = str_repeat("\n", $token['data']['spacecount']);
5149
					break;
5150
				case 'type2':
5151
					$space2 = str_repeat(' ', $token['data']['spacecount']);
5152
					break;
5153
				case 'type3':
5154
					$space3 = str_repeat("\n", $token['data']['spacecount']);
5155
					break;
5156
				case 'type4':
5157
					$space4 = str_repeat(' ', $token['data']['spacecount']);
5158
					break;
5159
				case 'type5':
5160
					$space5 = str_repeat("\n", $token['data']['spacecount']);
5161
					break;
5162
				}
5163
				break;
5164
			case 'tAttrSum': // SUM function with one parameter
5165
				$op = array_pop($formulaStrings);
5166
				$formulaStrings[] = "{$space1}{$space0}SUM($op)";
5167
				unset($space0, $space1);
5168
				break;
5169
			case 'tFunc': // function with fixed number of arguments
5170
			case 'tFuncV': // function with variable number of arguments
5171
				if ($token['data']['function'] != '') {
5172
					// normal function
5173
					$ops = array(); // array of operators
5174 View Code Duplication
					for ($i = 0; $i < $token['data']['args']; ++$i) {
5175
						$ops[] = array_pop($formulaStrings);
5176
					}
5177
					$ops = array_reverse($ops);
5178
					$formulaStrings[] = "$space1$space0{$token['data']['function']}(" . implode(',', $ops) . ")";
5179
					unset($space0, $space1);
5180
				} else {
5181
					// add-in function
5182
					$ops = array(); // array of operators
5183 View Code Duplication
					for ($i = 0; $i < $token['data']['args'] - 1; ++$i) {
5184
						$ops[] = array_pop($formulaStrings);
5185
					}
5186
					$ops = array_reverse($ops);
5187
					$function = array_pop($formulaStrings);
5188
					$formulaStrings[] = "$space1$space0$function(" . implode(',', $ops) . ")";
5189
					unset($space0, $space1);
5190
				}
5191
				break;
5192
			case 'tParen': // parenthesis
5193
				$expression = array_pop($formulaStrings);
5194
				$formulaStrings[] = "$space3$space2($expression$space5$space4)";
5195
				unset($space2, $space3, $space4, $space5);
5196
				break;
5197
			case 'tArray': // array constant
5198
				$constantArray = self::_readBIFF8ConstantArray($additionalData);
0 ignored issues
show
Bug introduced by
It seems like $additionalData defined by parameter $additionalData on line 5085 can also be of type array; however, PHPExcel_Reader_Excel5::_readBIFF8ConstantArray() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
5199
				$formulaStrings[] = $space1 . $space0 . $constantArray['value'];
5200
				$additionalData = substr($additionalData, $constantArray['size']); // bite of chunk of additional data
5201
				unset($space0, $space1);
5202
				break;
5203
			case 'tMemArea':
5204
				// bite off chunk of additional data
5205
				$cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($additionalData);
0 ignored issues
show
Bug introduced by
It seems like $additionalData defined by parameter $additionalData on line 5085 can also be of type array; however, PHPExcel_Reader_Excel5::...8CellRangeAddressList() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
5206
				$additionalData = substr($additionalData, $cellRangeAddressList['size']);
5207
				$formulaStrings[] = "$space1$space0{$token['data']}";
5208
				unset($space0, $space1);
5209
				break;
5210
			case 'tArea': // cell range address
5211
			case 'tBool': // boolean
5212
			case 'tErr': // error code
5213
			case 'tInt': // integer
5214
			case 'tMemErr':
5215
			case 'tMemFunc':
5216
			case 'tMissArg':
5217
			case 'tName':
5218
			case 'tNameX':
5219
			case 'tNum': // number
5220
			case 'tRef': // single cell reference
5221
			case 'tRef3d': // 3d cell reference
5222
			case 'tArea3d': // 3d cell range reference
5223
			case 'tRefN':
5224
			case 'tAreaN':
5225
			case 'tStr': // string
5226
				$formulaStrings[] = "$space1$space0{$token['data']}";
5227
				unset($space0, $space1);
5228
				break;
5229
			}
5230
		}
5231
		$formulaString = $formulaStrings[0];
5232
5233
		// for debug: dump the human readable formula
5234
		//echo '----' . "\n";
5235
		//echo 'Formula: ' . $formulaString;
5236
5237
		return $formulaString;
5238
	}
5239
5240
5241
	/**
5242
	 * Fetch next token from binary formula data
5243
	 *
5244
	 * @param string Formula data
5245
	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5246
	 * @return array
5247
	 * @throws Exception
5248
	 */
5249
	private function _getNextToken($formulaData, $baseCell = 'A1')
5250
	{
5251
		// offset: 0; size: 1; token id
5252
		$id = ord($formulaData[0]); // token id
5253
		$name = false; // initialize token name
5254
5255
		switch ($id) {
5256
		case 0x03: $name = 'tAdd';		$size = 1;	$data = '+';	break;
5257
		case 0x04: $name = 'tSub';		$size = 1;	$data = '-';	break;
5258
		case 0x05: $name = 'tMul';		$size = 1;	$data = '*';	break;
5259
		case 0x06: $name = 'tDiv';		$size = 1;	$data = '/';	break;
5260
		case 0x07: $name = 'tPower';	$size = 1;	$data = '^';	break;
5261
		case 0x08: $name = 'tConcat';	$size = 1;	$data = '&';	break;
5262
		case 0x09: $name = 'tLT';		$size = 1;	$data = '<';	break;
5263
		case 0x0A: $name = 'tLE';		$size = 1;	$data = '<=';	break;
5264
		case 0x0B: $name = 'tEQ';		$size = 1;	$data = '=';	break;
5265
		case 0x0C: $name = 'tGE';		$size = 1;	$data = '>=';	break;
5266
		case 0x0D: $name = 'tGT';		$size = 1;	$data = '>';	break;
5267
		case 0x0E: $name = 'tNE';		$size = 1;	$data = '<>';	break;
5268
		case 0x0F: $name = 'tIsect';	$size = 1;	$data = ' ';	break;
5269
		case 0x10: $name = 'tList';		$size = 1;	$data = ',';	break;
5270
		case 0x11: $name = 'tRange';	$size = 1;	$data = ':';	break;
5271
		case 0x12: $name = 'tUplus';	$size = 1;	$data = '+';	break;
5272
		case 0x13: $name = 'tUminus';	$size = 1;	$data = '-';	break;
5273
		case 0x14: $name = 'tPercent';	$size = 1;	$data = '%';	break;
5274
		case 0x15:	//	parenthesis
5275
			$name  = 'tParen';
5276
			$size  = 1;
5277
			$data = null;
5278
			break;
5279
		case 0x16:	//	missing argument
5280
			$name = 'tMissArg';
5281
			$size = 1;
5282
			$data = '';
5283
			break;
5284
		case 0x17:	//	string
5285
			$name = 'tStr';
5286
			// offset: 1; size: var; Unicode string, 8-bit string length
5287
			$string = self::_readUnicodeStringShort(substr($formulaData, 1));
5288
			$size = 1 + $string['size'];
5289
			$data = self::_UTF8toExcelDoubleQuoted($string['value']);
5290
			break;
5291
		case 0x19:	//	Special attribute
5292
			// offset: 1; size: 1; attribute type flags:
5293
			switch (ord($formulaData[1])) {
5294
			case 0x01:
5295
				$name = 'tAttrVolatile';
5296
				$size = 4;
5297
				$data = null;
5298
				break;
5299
			case 0x02:
5300
				$name = 'tAttrIf';
5301
				$size = 4;
5302
				$data = null;
5303
				break;
5304
			case 0x04:
5305
				$name = 'tAttrChoose';
5306
				// offset: 2; size: 2; number of choices in the CHOOSE function ($nc, number of parameters decreased by 1)
5307
				$nc = self::_GetInt2d($formulaData, 2);
5308
				// offset: 4; size: 2 * $nc
5309
				// offset: 4 + 2 * $nc; size: 2
5310
				$size = 2 * $nc + 6;
5311
				$data = null;
5312
				break;
5313
			case 0x08:
5314
				$name = 'tAttrSkip';
5315
				$size = 4;
5316
				$data = null;
5317
				break;
5318
			case 0x10:
5319
				$name = 'tAttrSum';
5320
				$size = 4;
5321
				$data = null;
5322
				break;
5323
			case 0x40:
5324
			case 0x41:
5325
				$name = 'tAttrSpace';
5326
				$size = 4;
5327
				// offset: 2; size: 2; space type and position
5328
				switch (ord($formulaData[2])) {
5329
				case 0x00:
5330
					$spacetype = 'type0';
5331
					break;
5332
				case 0x01:
5333
					$spacetype = 'type1';
5334
					break;
5335
				case 0x02:
5336
					$spacetype = 'type2';
5337
					break;
5338
				case 0x03:
5339
					$spacetype = 'type3';
5340
					break;
5341
				case 0x04:
5342
					$spacetype = 'type4';
5343
					break;
5344
				case 0x05:
5345
					$spacetype = 'type5';
5346
					break;
5347
				default:
5348
					throw new Exception('Unrecognized space type in tAttrSpace token');
5349
					break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
5350
				}
5351
				// offset: 3; size: 1; number of inserted spaces/carriage returns
5352
				$spacecount = ord($formulaData[3]);
5353
5354
				$data = array('spacetype' => $spacetype, 'spacecount' => $spacecount);
5355
				break;
5356
			default:
5357
				throw new Exception('Unrecognized attribute flag in tAttr token');
5358
				break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
5359
			}
5360
			break;
5361
		case 0x1C:	//	error code
5362
			// offset: 1; size: 1; error code
5363
			$name = 'tErr';
5364
			$size = 2;
5365
			$data = self::_mapErrorCode(ord($formulaData[1]));
5366
			break;
5367
		case 0x1D:	//	boolean
5368
			// offset: 1; size: 1; 0 = false, 1 = true;
5369
			$name = 'tBool';
5370
			$size = 2;
5371
			$data = ord($formulaData[1]) ? 'TRUE' : 'FALSE';
5372
			break;
5373
		case 0x1E:	//	integer
5374
			// offset: 1; size: 2; unsigned 16-bit integer
5375
			$name = 'tInt';
5376
			$size = 3;
5377
			$data = self::_GetInt2d($formulaData, 1);
5378
			break;
5379
		case 0x1F:	//	number
5380
			// offset: 1; size: 8;
5381
			$name = 'tNum';
5382
			$size = 9;
5383
			$data = self::_extractNumber(substr($formulaData, 1));
5384
			$data = str_replace(',', '.', (string)$data); // in case non-English locale
5385
			break;
5386
		case 0x20:	//	array constant
5387
		case 0x40:
5388
		case 0x60:
5389
			// offset: 1; size: 7; not used
5390
			$name = 'tArray';
5391
			$size = 8;
5392
			$data = null;
5393
			break;
5394
		case 0x21:	//	function with fixed number of arguments
5395
		case 0x41:
5396
		case 0x61:
5397
			$name = 'tFunc';
5398
			$size = 3;
5399
			// offset: 1; size: 2; index to built-in sheet function
5400
			switch (self::_GetInt2d($formulaData, 1)) {
5401
			case   2: $function = 'ISNA'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5402
			case   3: $function = 'ISERROR'; 		$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5403
			case  10: $function = 'NA'; 			$args = 0; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5404
			case  15: $function = 'SIN'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5405
			case  16: $function = 'COS'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5406
			case  17: $function = 'TAN'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5407
			case  18: $function = 'ATAN'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5408
			case  19: $function = 'PI'; 			$args = 0; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5409
			case  20: $function = 'SQRT'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5410
			case  21: $function = 'EXP'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5411
			case  22: $function = 'LN'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5412
			case  23: $function = 'LOG10'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5413
			case  24: $function = 'ABS'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5414
			case  25: $function = 'INT'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5415
			case  26: $function = 'SIGN'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5416
			case  27: $function = 'ROUND'; 			$args = 2; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5417
			case  30: $function = 'REPT'; 			$args = 2; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5418
			case  31: $function = 'MID'; 			$args = 3; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5419
			case  32: $function = 'LEN'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5420
			case  33: $function = 'VALUE'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5421
			case  34: $function = 'TRUE'; 			$args = 0; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5422
			case  35: $function = 'FALSE'; 			$args = 0; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5423
			case  38: $function = 'NOT'; 			$args = 1; 	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5424
			case  39: $function = 'MOD'; 			$args = 2;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5425
			case  40: $function = 'DCOUNT'; 		$args = 3;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5426
			case  41: $function = 'DSUM'; 			$args = 3;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5427
			case  42: $function = 'DAVERAGE'; 		$args = 3;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5428
			case  43: $function = 'DMIN'; 			$args = 3;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5429
			case  44: $function = 'DMAX'; 			$args = 3;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5430
			case  45: $function = 'DSTDEV'; 		$args = 3;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5431
			case  48: $function = 'TEXT'; 			$args = 2;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5432
			case  61: $function = 'MIRR'; 			$args = 3;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5433
			case  63: $function = 'RAND'; 			$args = 0;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5434
			case  65: $function = 'DATE'; 			$args = 3;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5435
			case  66: $function = 'TIME'; 			$args = 3;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5436
			case  67: $function = 'DAY'; 			$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5437
			case  68: $function = 'MONTH'; 			$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5438
			case  69: $function = 'YEAR'; 			$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5439
			case  71: $function = 'HOUR'; 			$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5440
			case  72: $function = 'MINUTE'; 		$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5441
			case  73: $function = 'SECOND'; 		$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5442
			case  74: $function = 'NOW'; 			$args = 0;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5443
			case  75: $function = 'AREAS'; 			$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5444
			case  76: $function = 'ROWS'; 			$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5445
			case  77: $function = 'COLUMNS'; 		$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5446
			case  83: $function = 'TRANSPOSE'; 		$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5447
			case  86: $function = 'TYPE'; 			$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5448
			case  97: $function = 'ATAN2'; 			$args = 2;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5449
			case  98: $function = 'ASIN'; 			$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5450
			case  99: $function = 'ACOS'; 			$args = 1;	break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5451
			case 105: $function = 'ISREF'; 			$args = 1;	break;
5452
			case 111: $function = 'CHAR'; 			$args = 1;	break;
5453
			case 112: $function = 'LOWER'; 			$args = 1;	break;
5454
			case 113: $function = 'UPPER'; 			$args = 1;	break;
5455
			case 114: $function = 'PROPER'; 		$args = 1;	break;
5456
			case 117: $function = 'EXACT'; 			$args = 2;	break;
5457
			case 118: $function = 'TRIM'; 			$args = 1;	break;
5458
			case 119: $function = 'REPLACE'; 		$args = 4;	break;
5459
			case 121: $function = 'CODE'; 			$args = 1;	break;
5460
			case 126: $function = 'ISERR'; 			$args = 1;	break;
5461
			case 127: $function = 'ISTEXT'; 		$args = 1;	break;
5462
			case 128: $function = 'ISNUMBER'; 		$args = 1;	break;
5463
			case 129: $function = 'ISBLANK'; 		$args = 1;	break;
5464
			case 130: $function = 'T'; 				$args = 1;	break;
5465
			case 131: $function = 'N'; 				$args = 1;	break;
5466
			case 140: $function = 'DATEVALUE'; 		$args = 1;	break;
5467
			case 141: $function = 'TIMEVALUE'; 		$args = 1;	break;
5468
			case 142: $function = 'SLN'; 			$args = 3;	break;
5469
			case 143: $function = 'SYD'; 			$args = 4;	break;
5470
			case 162: $function = 'CLEAN'; 			$args = 1;	break;
5471
			case 163: $function = 'MDETERM'; 		$args = 1;	break;
5472
			case 164: $function = 'MINVERSE'; 		$args = 1;	break;
5473
			case 165: $function = 'MMULT'; 			$args = 2;	break;
5474
			case 184: $function = 'FACT'; 			$args = 1;	break;
5475
			case 189: $function = 'DPRODUCT'; 		$args = 3;	break;
5476
			case 190: $function = 'ISNONTEXT'; 		$args = 1;	break;
5477
			case 195: $function = 'DSTDEVP'; 		$args = 3;	break;
5478
			case 196: $function = 'DVARP'; 			$args = 3;	break;
5479
			case 198: $function = 'ISLOGICAL'; 		$args = 1;	break;
5480
			case 199: $function = 'DCOUNTA'; 		$args = 3;	break;
5481
			case 207: $function = 'REPLACEB'; 		$args = 4;	break;
5482
			case 210: $function = 'MIDB'; 			$args = 3;	break;
5483
			case 211: $function = 'LENB'; 			$args = 1;	break;
5484
			case 212: $function = 'ROUNDUP'; 		$args = 2;	break;
5485
			case 213: $function = 'ROUNDDOWN'; 		$args = 2;	break;
5486
			case 214: $function = 'ASC'; 			$args = 1;	break;
5487
			case 215: $function = 'DBCS'; 			$args = 1;	break;
5488
			case 221: $function = 'TODAY'; 			$args = 0;	break;
5489
			case 229: $function = 'SINH'; 			$args = 1;	break;
5490
			case 230: $function = 'COSH'; 			$args = 1;	break;
5491
			case 231: $function = 'TANH'; 			$args = 1;	break;
5492
			case 232: $function = 'ASINH'; 			$args = 1;	break;
5493
			case 233: $function = 'ACOSH'; 			$args = 1;	break;
5494
			case 234: $function = 'ATANH'; 			$args = 1;	break;
5495
			case 235: $function = 'DGET'; 			$args = 3;	break;
5496
			case 244: $function = 'INFO'; 			$args = 1;	break;
5497
			case 252: $function = 'FREQUENCY'; 		$args = 2;	break;
5498
			case 261: $function = 'ERROR.TYPE'; 	$args = 1;	break;
5499
			case 271: $function = 'GAMMALN'; 		$args = 1;	break;
5500
			case 273: $function = 'BINOMDIST'; 		$args = 4;	break;
5501
			case 274: $function = 'CHIDIST'; 		$args = 2;	break;
5502
			case 275: $function = 'CHIINV'; 		$args = 2;	break;
5503
			case 276: $function = 'COMBIN'; 		$args = 2;	break;
5504
			case 277: $function = 'CONFIDENCE'; 	$args = 3;	break;
5505
			case 278: $function = 'CRITBINOM'; 		$args = 3;	break;
5506
			case 279: $function = 'EVEN'; 			$args = 1;	break;
5507
			case 280: $function = 'EXPONDIST'; 		$args = 3;	break;
5508
			case 281: $function = 'FDIST'; 			$args = 3;	break;
5509
			case 282: $function = 'FINV'; 			$args = 3;	break;
5510
			case 283: $function = 'FISHER'; 		$args = 1;	break;
5511
			case 284: $function = 'FISHERINV'; 		$args = 1;	break;
5512
			case 285: $function = 'FLOOR'; 			$args = 2;	break;
5513
			case 286: $function = 'GAMMADIST'; 		$args = 4;	break;
5514
			case 287: $function = 'GAMMAINV'; 		$args = 3;	break;
5515
			case 288: $function = 'CEILING'; 		$args = 2;	break;
5516
			case 289: $function = 'HYPGEOMDIST';	$args = 4;	break;
5517
			case 290: $function = 'LOGNORMDIST';	$args = 3;	break;
5518
			case 291: $function = 'LOGINV';			$args = 3;	break;
5519
			case 292: $function = 'NEGBINOMDIST';	$args = 3;	break;
5520
			case 293: $function = 'NORMDIST';		$args = 4;	break;
5521
			case 294: $function = 'NORMSDIST';		$args = 1;	break;
5522
			case 295: $function = 'NORMINV';		$args = 3;	break;
5523
			case 296: $function = 'NORMSINV';		$args = 1;	break;
5524
			case 297: $function = 'STANDARDIZE';	$args = 3;	break;
5525
			case 298: $function = 'ODD';			$args = 1;	break;
5526
			case 299: $function = 'PERMUT';			$args = 2;	break;
5527
			case 300: $function = 'POISSON';		$args = 3;	break;
5528
			case 301: $function = 'TDIST';			$args = 3;	break;
5529
			case 302: $function = 'WEIBULL';		$args = 4;	break;
5530
			case 303: $function = 'SUMXMY2';		$args = 2;	break;
5531
			case 304: $function = 'SUMX2MY2';		$args = 2;	break;
5532
			case 305: $function = 'SUMX2PY2';		$args = 2;	break;
5533
			case 306: $function = 'CHITEST';		$args = 2;	break;
5534
			case 307: $function = 'CORREL';			$args = 2;	break;
5535
			case 308: $function = 'COVAR';			$args = 2;	break;
5536
			case 309: $function = 'FORECAST';		$args = 3;	break;
5537
			case 310: $function = 'FTEST';			$args = 2;	break;
5538
			case 311: $function = 'INTERCEPT';		$args = 2;	break;
5539
			case 312: $function = 'PEARSON';		$args = 2;	break;
5540
			case 313: $function = 'RSQ';			$args = 2;	break;
5541
			case 314: $function = 'STEYX';			$args = 2;	break;
5542
			case 315: $function = 'SLOPE';			$args = 2;	break;
5543
			case 316: $function = 'TTEST';			$args = 4;	break;
5544
			case 325: $function = 'LARGE';			$args = 2;	break;
5545
			case 326: $function = 'SMALL';			$args = 2;	break;
5546
			case 327: $function = 'QUARTILE';		$args = 2;	break;
5547
			case 328: $function = 'PERCENTILE';		$args = 2;	break;
5548
			case 331: $function = 'TRIMMEAN';		$args = 2;	break;
5549
			case 332: $function = 'TINV';			$args = 2;	break;
5550
			case 337: $function = 'POWER';			$args = 2;	break;
5551
			case 342: $function = 'RADIANS';		$args = 1;	break;
5552
			case 343: $function = 'DEGREES';		$args = 1;	break;
5553
			case 346: $function = 'COUNTIF';		$args = 2;	break;
5554
			case 347: $function = 'COUNTBLANK';		$args = 1;	break;
5555
			case 350: $function = 'ISPMT';			$args = 4;	break;
5556
			case 351: $function = 'DATEDIF';		$args = 3;	break;
5557
			case 352: $function = 'DATESTRING';		$args = 1;	break;
5558
			case 353: $function = 'NUMBERSTRING';	$args = 2;	break;
5559
			case 360: $function = 'PHONETIC';		$args = 1;	break;
5560
			case 368: $function = 'BAHTTEXT';		$args = 1;	break;
5561
			default:
5562
				throw new Exception('Unrecognized function in formula');
5563
				break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
5564
			}
5565
			$data = array('function' => $function, 'args' => $args);
5566
			break;
5567
		case 0x22:	//	function with variable number of arguments
5568
		case 0x42:
5569
		case 0x62:
5570
			$name = 'tFuncV';
5571
			$size = 4;
5572
			// offset: 1; size: 1; number of arguments
5573
			$args = ord($formulaData[1]);
5574
			// offset: 2: size: 2; index to built-in sheet function
5575
			$index = self::_GetInt2d($formulaData, 2);
5576
			switch ($index) {
5577
			case   0: $function = 'COUNT';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5578
			case   1: $function = 'IF';				break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5579
			case   4: $function = 'SUM';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5580
			case   5: $function = 'AVERAGE';		break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5581
			case   6: $function = 'MIN';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5582
			case   7: $function = 'MAX';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5583
			case   8: $function = 'ROW';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5584
			case   9: $function = 'COLUMN';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5585
			case  11: $function = 'NPV';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5586
			case  12: $function = 'STDEV';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5587
			case  13: $function = 'DOLLAR';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5588
			case  14: $function = 'FIXED';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5589
			case  28: $function = 'LOOKUP';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5590
			case  29: $function = 'INDEX';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5591
			case  36: $function = 'AND';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5592
			case  37: $function = 'OR';				break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5593
			case  46: $function = 'VAR';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5594
			case  49: $function = 'LINEST';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5595
			case  50: $function = 'TREND';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5596
			case  51: $function = 'LOGEST';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5597
			case  52: $function = 'GROWTH';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5598
			case  56: $function = 'PV';				break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5599
			case  57: $function = 'FV';				break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5600
			case  58: $function = 'NPER';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5601
			case  59: $function = 'PMT';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5602
			case  60: $function = 'RATE';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5603
			case  62: $function = 'IRR';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5604
			case  64: $function = 'MATCH';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5605
			case  70: $function = 'WEEKDAY';		break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5606
			case  78: $function = 'OFFSET';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5607
			case  82: $function = 'SEARCH';			break;
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5608
			case 100: $function = 'CHOOSE';			break;
5609
			case 101: $function = 'HLOOKUP';		break;
5610
			case 102: $function = 'VLOOKUP';		break;
5611
			case 109: $function = 'LOG';			break;
5612
			case 115: $function = 'LEFT';			break;
5613
			case 116: $function = 'RIGHT';			break;
5614
			case 120: $function = 'SUBSTITUTE';		break;
5615
			case 124: $function = 'FIND';			break;
5616
			case 125: $function = 'CELL';			break;
5617
			case 144: $function = 'DDB';			break;
5618
			case 148: $function = 'INDIRECT';		break;
5619
			case 167: $function = 'IPMT';			break;
5620
			case 168: $function = 'PPMT';			break;
5621
			case 169: $function = 'COUNTA';			break;
5622
			case 183: $function = 'PRODUCT';		break;
5623
			case 193: $function = 'STDEVP';			break;
5624
			case 194: $function = 'VARP';			break;
5625
			case 197: $function = 'TRUNC';			break;
5626
			case 204: $function = 'USDOLLAR';		break;
5627
			case 205: $function = 'FINDB';			break;
5628
			case 206: $function = 'SEARCHB';		break;
5629
			case 208: $function = 'LEFTB';			break;
5630
			case 209: $function = 'RIGHTB';			break;
5631
			case 216: $function = 'RANK';			break;
5632
			case 219: $function = 'ADDRESS';		break;
5633
			case 220: $function = 'DAYS360';		break;
5634
			case 222: $function = 'VDB';			break;
5635
			case 227: $function = 'MEDIAN';			break;
5636
			case 228: $function = 'SUMPRODUCT';		break;
5637
			case 247: $function = 'DB';				break;
5638
			case 255: $function = '';				break;
5639
			case 269: $function = 'AVEDEV';			break;
5640
			case 270: $function = 'BETADIST';		break;
5641
			case 272: $function = 'BETAINV';		break;
5642
			case 317: $function = 'PROB';			break;
5643
			case 318: $function = 'DEVSQ';			break;
5644
			case 319: $function = 'GEOMEAN';		break;
5645
			case 320: $function = 'HARMEAN';		break;
5646
			case 321: $function = 'SUMSQ';			break;
5647
			case 322: $function = 'KURT';			break;
5648
			case 323: $function = 'SKEW';			break;
5649
			case 324: $function = 'ZTEST';			break;
5650
			case 329: $function = 'PERCENTRANK';	break;
5651
			case 330: $function = 'MODE';			break;
5652
			case 336: $function = 'CONCATENATE';	break;
5653
			case 344: $function = 'SUBTOTAL';		break;
5654
			case 345: $function = 'SUMIF';			break;
5655
			case 354: $function = 'ROMAN';			break;
5656
			case 358: $function = 'GETPIVOTDATA';	break;
5657
			case 359: $function = 'HYPERLINK';		break;
5658
			case 361: $function = 'AVERAGEA';		break;
5659
			case 362: $function = 'MAXA';			break;
5660
			case 363: $function = 'MINA';			break;
5661
			case 364: $function = 'STDEVPA';		break;
5662
			case 365: $function = 'VARPA';			break;
5663
			case 366: $function = 'STDEVA';			break;
5664
			case 367: $function = 'VARA';			break;
5665
			default:
5666
				throw new Exception('Unrecognized function in formula');
5667
				break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
5668
			}
5669
			$data = array('function' => $function, 'args' => $args);
5670
			break;
5671
		case 0x23:	//	index to defined name
5672
		case 0x43:
5673
		case 0x63:
5674
			$name = 'tName';
5675
			$size = 5;
5676
			// offset: 1; size: 2; one-based index to definedname record
5677
			$definedNameIndex = self::_GetInt2d($formulaData, 1) - 1;
5678
			// offset: 2; size: 2; not used
5679
			$data = $this->_definedname[$definedNameIndex]['name'];
5680
			break;
5681
		case 0x24:	//	single cell reference e.g. A5
5682
		case 0x44:
5683
		case 0x64:
5684
			$name = 'tRef';
5685
			$size = 5;
5686
			$data = $this->_readBIFF8CellAddress(substr($formulaData, 1, 4));
5687
			break;
5688
		case 0x25:	//	cell range reference to cells in the same sheet (2d)
5689
		case 0x45:
5690
		case 0x65:
5691
			$name = 'tArea';
5692
			$size = 9;
5693
			$data = $this->_readBIFF8CellRangeAddress(substr($formulaData, 1, 8));
5694
			break;
5695
		case 0x26:	//	Constant reference sub-expression
5696
		case 0x46:
5697 View Code Duplication
		case 0x66:
5698
			$name = 'tMemArea';
5699
			// offset: 1; size: 4; not used
5700
			// offset: 5; size: 2; size of the following subexpression
5701
			$subSize = self::_GetInt2d($formulaData, 5);
5702
			$size = 7 + $subSize;
5703
			$data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
5704
			break;
5705
		case 0x27:	//	Deleted constant reference sub-expression
5706
		case 0x47:
5707 View Code Duplication
		case 0x67:
5708
			$name = 'tMemErr';
5709
			// offset: 1; size: 4; not used
5710
			// offset: 5; size: 2; size of the following subexpression
5711
			$subSize = self::_GetInt2d($formulaData, 5);
5712
			$size = 7 + $subSize;
5713
			$data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
5714
			break;
5715
		case 0x29:	//	Variable reference sub-expression
5716
		case 0x49:
5717 View Code Duplication
		case 0x69:
5718
			$name = 'tMemFunc';
5719
			// offset: 1; size: 2; size of the following sub-expression
5720
			$subSize = self::_GetInt2d($formulaData, 1);
5721
			$size = 3 + $subSize;
5722
			$data = $this->_getFormulaFromData(substr($formulaData, 3, $subSize));
5723
			break;
5724
5725
		case 0x2C: // Relative 2d cell reference reference, used in shared formulas and some other places
5726
		case 0x4C:
5727
		case 0x6C:
5728
			$name = 'tRefN';
5729
			$size = 5;
5730
			$data = $this->_readBIFF8CellAddressB(substr($formulaData, 1, 4), $baseCell);
5731
			break;
5732
5733
		case 0x2D:	//	Relative 2d range reference
5734
		case 0x4D:
5735
		case 0x6D:
5736
			$name = 'tAreaN';
5737
			$size = 9;
5738
			$data = $this->_readBIFF8CellRangeAddressB(substr($formulaData, 1, 8), $baseCell);
5739
			break;
5740
5741
		case 0x39:	//	External name
5742
		case 0x59:
5743
		case 0x79:
5744
			$name = 'tNameX';
5745
			$size = 7;
5746
			// offset: 1; size: 2; index to REF entry in EXTERNSHEET record
5747
			// offset: 3; size: 2; one-based index to DEFINEDNAME or EXTERNNAME record
5748
			$index = self::_GetInt2d($formulaData, 3);
5749
			// assume index is to EXTERNNAME record
5750
			$data = $this->_externalNames[$index - 1]['name'];
5751
			// offset: 5; size: 2; not used
5752
			break;
5753
5754
		case 0x3A:	//	3d reference to cell
5755
		case 0x5A:
5756 View Code Duplication
		case 0x7A:
5757
			$name = 'tRef3d';
5758
			$size = 7;
5759
5760
			try {
5761
				// offset: 1; size: 2; index to REF entry
5762
				$sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
5763
				// offset: 3; size: 4; cell address
5764
				$cellAddress = $this->_readBIFF8CellAddress(substr($formulaData, 3, 4));
5765
5766
				$data = "$sheetRange!$cellAddress";
5767
			} catch (Exception $e) {
5768
				// deleted sheet reference
5769
				$data = '#REF!';
5770
			}
5771
5772
			break;
5773
		case 0x3B:	//	3d reference to cell range
5774
		case 0x5B:
5775 View Code Duplication
		case 0x7B:
5776
			$name = 'tArea3d';
5777
			$size = 11;
5778
5779
			try {
5780
				// offset: 1; size: 2; index to REF entry
5781
				$sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
5782
				// offset: 3; size: 8; cell address
5783
				$cellRangeAddress = $this->_readBIFF8CellRangeAddress(substr($formulaData, 3, 8));
5784
5785
				$data = "$sheetRange!$cellRangeAddress";
5786
			} catch (Exception $e) {
5787
				// deleted sheet reference
5788
				$data = '#REF!';
5789
			}
5790
5791
			break;
5792
		// Unknown cases	// don't know how to deal with
5793
		default:
5794
			throw new Exception('Unrecognized token ' . sprintf('%02X', $id) . ' in formula');
5795
			break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
5796
		}
5797
5798
		return array(
5799
			'id' => $id,
5800
			'name' => $name,
5801
			'size' => $size,
5802
			'data' => $data,
5803
		);
5804
	}
5805
5806
5807
	/**
5808
	 * Reads a cell address in BIFF8 e.g. 'A2' or '$A$2'
5809
	 * section 3.3.4
5810
	 *
5811
	 * @param string $cellAddressStructure
5812
	 * @return string
5813
	 */
5814
	private function _readBIFF8CellAddress($cellAddressStructure)
5815
	{
5816
		// offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
5817
		$row = self::_GetInt2d($cellAddressStructure, 0) + 1;
5818
5819
		// offset: 2; size: 2; index to column or column offset + relative flags
5820
5821
			// bit: 7-0; mask 0x00FF; column index
5822
			$column = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($cellAddressStructure, 2));
5823
5824
			// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
5825
			if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) {
5826
				$column = '$' . $column;
5827
			}
5828
			// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
5829
			if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) {
5830
				$row = '$' . $row;
5831
			}
5832
5833
		return $column . $row;
5834
	}
5835
5836
5837
	/**
5838
	 * Reads a cell address in BIFF8 for shared formulas. Uses positive and negative values for row and column
5839
	 * to indicate offsets from a base cell
5840
	 * section 3.3.4
5841
	 *
5842
	 * @param string $cellAddressStructure
5843
	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
5844
	 * @return string
5845
	 */
5846
	private function _readBIFF8CellAddressB($cellAddressStructure, $baseCell = 'A1')
5847
	{
5848
		list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
5849
		$baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
5850
5851
		// offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
5852
			$rowIndex = self::_GetInt2d($cellAddressStructure, 0);
5853
			$row = self::_GetInt2d($cellAddressStructure, 0) + 1;
5854
5855
		// offset: 2; size: 2; index to column or column offset + relative flags
5856
5857
			// bit: 7-0; mask 0x00FF; column index
5858
			$colIndex = 0x00FF & self::_GetInt2d($cellAddressStructure, 2);
5859
5860
			// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
5861 View Code Duplication
			if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) {
5862
				$column = PHPExcel_Cell::stringFromColumnIndex($colIndex);
5863
				$column = '$' . $column;
5864
			} else {
5865
				$colIndex = ($colIndex <= 127) ? $colIndex : $colIndex - 256;
5866
				$column = PHPExcel_Cell::stringFromColumnIndex($baseCol + $colIndex);
5867
			}
5868
5869
			// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
5870
			if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) {
5871
				$row = '$' . $row;
5872
			} else {
5873
				$rowIndex = ($rowIndex <= 32767) ? $rowIndex : $rowIndex - 65536;
5874
				$row = $baseRow + $rowIndex;
5875
			}
5876
5877
		return $column . $row;
5878
	}
5879
5880
5881
	/**
5882
	 * Reads a cell range address in BIFF5 e.g. 'A2:B6' or 'A1'
5883
	 * always fixed range
5884
	 * section 2.5.14
5885
	 *
5886
	 * @param string $subData
5887
	 * @return string
5888
	 * @throws Exception
5889
	 */
5890
	private function _readBIFF5CellRangeAddressFixed($subData)
5891
	{
5892
		// offset: 0; size: 2; index to first row
5893
		$fr = self::_GetInt2d($subData, 0) + 1;
5894
5895
		// offset: 2; size: 2; index to last row
5896
		$lr = self::_GetInt2d($subData, 2) + 1;
5897
5898
		// offset: 4; size: 1; index to first column
5899
		$fc = ord($subData{4});
5900
5901
		// offset: 5; size: 1; index to last column
5902
		$lc = ord($subData{5});
5903
5904
		// check values
5905
		if ($fr > $lr || $fc > $lc) {
5906
			throw new Exception('Not a cell range address');
5907
		}
5908
5909
		// column index to letter
5910
		$fc = PHPExcel_Cell::stringFromColumnIndex($fc);
5911
		$lc = PHPExcel_Cell::stringFromColumnIndex($lc);
5912
5913
		if ($fr == $lr and $fc == $lc) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
5914
			return "$fc$fr";
5915
		}
5916
		return "$fc$fr:$lc$lr";
5917
	}
5918
5919
5920
	/**
5921
	 * Reads a cell range address in BIFF8 e.g. 'A2:B6' or 'A1'
5922
	 * always fixed range
5923
	 * section 2.5.14
5924
	 *
5925
	 * @param string $subData
5926
	 * @return string
5927
	 * @throws Exception
5928
	 */
5929
	private function _readBIFF8CellRangeAddressFixed($subData)
5930
	{
5931
		// offset: 0; size: 2; index to first row
5932
		$fr = self::_GetInt2d($subData, 0) + 1;
5933
5934
		// offset: 2; size: 2; index to last row
5935
		$lr = self::_GetInt2d($subData, 2) + 1;
5936
5937
		// offset: 4; size: 2; index to first column
5938
		$fc = self::_GetInt2d($subData, 4);
5939
5940
		// offset: 6; size: 2; index to last column
5941
		$lc = self::_GetInt2d($subData, 6);
5942
5943
		// check values
5944
		if ($fr > $lr || $fc > $lc) {
5945
			throw new Exception('Not a cell range address');
5946
		}
5947
5948
		// column index to letter
5949
		$fc = PHPExcel_Cell::stringFromColumnIndex($fc);
5950
		$lc = PHPExcel_Cell::stringFromColumnIndex($lc);
5951
5952
		if ($fr == $lr and $fc == $lc) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
5953
			return "$fc$fr";
5954
		}
5955
		return "$fc$fr:$lc$lr";
5956
	}
5957
5958
5959
	/**
5960
	 * Reads a cell range address in BIFF8 e.g. 'A2:B6' or '$A$2:$B$6'
5961
	 * there are flags indicating whether column/row index is relative
5962
	 * section 3.3.4
5963
	 *
5964
	 * @param string $subData
5965
	 * @return string
5966
	 */
5967
	private function _readBIFF8CellRangeAddress($subData)
5968
	{
5969
		// todo: if cell range is just a single cell, should this funciton
5970
		// not just return e.g. 'A1' and not 'A1:A1' ?
5971
5972
		// offset: 0; size: 2; index to first row (0... 65535) (or offset (-32768... 32767))
5973
			$fr = self::_GetInt2d($subData, 0) + 1;
5974
5975
		// offset: 2; size: 2; index to last row (0... 65535) (or offset (-32768... 32767))
5976
			$lr = self::_GetInt2d($subData, 2) + 1;
5977
5978
		// offset: 4; size: 2; index to first column or column offset + relative flags
5979
5980
		// bit: 7-0; mask 0x00FF; column index
5981
		$fc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 4));
5982
5983
		// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
5984
		if (!(0x4000 & self::_GetInt2d($subData, 4))) {
5985
			$fc = '$' . $fc;
5986
		}
5987
5988
		// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
5989
		if (!(0x8000 & self::_GetInt2d($subData, 4))) {
5990
			$fr = '$' . $fr;
5991
		}
5992
5993
		// offset: 6; size: 2; index to last column or column offset + relative flags
5994
5995
		// bit: 7-0; mask 0x00FF; column index
5996
		$lc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 6));
5997
5998
		// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
5999
		if (!(0x4000 & self::_GetInt2d($subData, 6))) {
6000
			$lc = '$' . $lc;
6001
		}
6002
6003
		// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6004
		if (!(0x8000 & self::_GetInt2d($subData, 6))) {
6005
			$lr = '$' . $lr;
6006
		}
6007
6008
		return "$fc$fr:$lc$lr";
6009
	}
6010
6011
6012
	/**
6013
	 * Reads a cell range address in BIFF8 for shared formulas. Uses positive and negative values for row and column
6014
	 * to indicate offsets from a base cell
6015
	 * section 3.3.4
6016
	 *
6017
	 * @param string $subData
6018
	 * @param string $baseCell Base cell
6019
	 * @return string Cell range address
6020
	 */
6021
	private function _readBIFF8CellRangeAddressB($subData, $baseCell = 'A1')
6022
	{
6023
		list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
6024
		$baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
6025
6026
		// TODO: if cell range is just a single cell, should this funciton
6027
		// not just return e.g. 'A1' and not 'A1:A1' ?
6028
6029
		// offset: 0; size: 2; first row
6030
		$frIndex = self::_GetInt2d($subData, 0); // adjust below
6031
6032
		// offset: 2; size: 2; relative index to first row (0... 65535) should be treated as offset (-32768... 32767)
6033
		$lrIndex = self::_GetInt2d($subData, 2); // adjust below
6034
6035
		// offset: 4; size: 2; first column with relative/absolute flags
6036
6037
		// bit: 7-0; mask 0x00FF; column index
6038
		$fcIndex = 0x00FF & self::_GetInt2d($subData, 4);
6039
6040
		// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6041 View Code Duplication
		if (!(0x4000 & self::_GetInt2d($subData, 4))) {
6042
			// absolute column index
6043
			$fc = PHPExcel_Cell::stringFromColumnIndex($fcIndex);
6044
			$fc = '$' . $fc;
6045
		} else {
6046
			// column offset
6047
			$fcIndex = ($fcIndex <= 127) ? $fcIndex : $fcIndex - 256;
6048
			$fc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $fcIndex);
6049
		}
6050
6051
		// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6052 View Code Duplication
		if (!(0x8000 & self::_GetInt2d($subData, 4))) {
6053
			// absolute row index
6054
			$fr = $frIndex + 1;
6055
			$fr = '$' . $fr;
6056
		} else {
6057
			// row offset
6058
			$frIndex = ($frIndex <= 32767) ? $frIndex : $frIndex - 65536;
6059
			$fr = $baseRow + $frIndex;
6060
		}
6061
6062
		// offset: 6; size: 2; last column with relative/absolute flags
6063
6064
		// bit: 7-0; mask 0x00FF; column index
6065
		$lcIndex = 0x00FF & self::_GetInt2d($subData, 6);
6066
		$lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
6067
		$lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
6068
6069
		// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
6070 View Code Duplication
		if (!(0x4000 & self::_GetInt2d($subData, 6))) {
6071
			// absolute column index
6072
			$lc = PHPExcel_Cell::stringFromColumnIndex($lcIndex);
6073
			$lc = '$' . $lc;
6074
		} else {
6075
			// column offset
6076
			$lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
6077
			$lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
6078
		}
6079
6080
		// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
6081 View Code Duplication
		if (!(0x8000 & self::_GetInt2d($subData, 6))) {
6082
			// absolute row index
6083
			$lr = $lrIndex + 1;
6084
			$lr = '$' . $lr;
6085
		} else {
6086
			// row offset
6087
			$lrIndex = ($lrIndex <= 32767) ? $lrIndex : $lrIndex - 65536;
6088
			$lr = $baseRow + $lrIndex;
6089
		}
6090
6091
		return "$fc$fr:$lc$lr";
6092
	}
6093
6094
6095
	/**
6096
	 * Read BIFF8 cell range address list
6097
	 * section 2.5.15
6098
	 *
6099
	 * @param string $subData
6100
	 * @return array
6101
	 */
6102 View Code Duplication
	private function _readBIFF8CellRangeAddressList($subData)
6103
	{
6104
		$cellRangeAddresses = array();
6105
6106
		// offset: 0; size: 2; number of the following cell range addresses
6107
		$nm = self::_GetInt2d($subData, 0);
6108
6109
		$offset = 2;
6110
		// offset: 2; size: 8 * $nm; list of $nm (fixed) cell range addresses
6111
		for ($i = 0; $i < $nm; ++$i) {
6112
			$cellRangeAddresses[] = $this->_readBIFF8CellRangeAddressFixed(substr($subData, $offset, 8));
6113
			$offset += 8;
6114
		}
6115
6116
		return array(
6117
			'size' => 2 + 8 * $nm,
6118
			'cellRangeAddresses' => $cellRangeAddresses,
6119
		);
6120
	}
6121
6122
6123
	/**
6124
	 * Read BIFF5 cell range address list
6125
	 * section 2.5.15
6126
	 *
6127
	 * @param string $subData
6128
	 * @return array
6129
	 */
6130 View Code Duplication
	private function _readBIFF5CellRangeAddressList($subData)
6131
	{
6132
		$cellRangeAddresses = array();
6133
6134
		// offset: 0; size: 2; number of the following cell range addresses
6135
		$nm = self::_GetInt2d($subData, 0);
6136
6137
		$offset = 2;
6138
		// offset: 2; size: 6 * $nm; list of $nm (fixed) cell range addresses
6139
		for ($i = 0; $i < $nm; ++$i) {
6140
			$cellRangeAddresses[] = $this->_readBIFF5CellRangeAddressFixed(substr($subData, $offset, 6));
6141
			$offset += 6;
6142
		}
6143
6144
		return array(
6145
			'size' => 2 + 6 * $nm,
6146
			'cellRangeAddresses' => $cellRangeAddresses,
6147
		);
6148
	}
6149
6150
6151
	/**
6152
	 * Get a sheet range like Sheet1:Sheet3 from REF index
6153
	 * Note: If there is only one sheet in the range, one gets e.g Sheet1
6154
	 * It can also happen that the REF structure uses the -1 (FFFF) code to indicate deleted sheets,
6155
	 * in which case an exception is thrown
6156
	 *
6157
	 * @param int $index
6158
	 * @return string|false
6159
	 * @throws Exception
6160
	 */
6161
	private function _readSheetRangeByRefIndex($index)
6162
	{
6163
		if (isset($this->_ref[$index])) {
6164
6165
			$type = $this->_externalBooks[$this->_ref[$index]['externalBookIndex']]['type'];
6166
6167
			switch ($type) {
6168
				case 'internal':
6169
					// check if we have a deleted 3d reference
6170
					if ($this->_ref[$index]['firstSheetIndex'] == 0xFFFF or $this->_ref[$index]['lastSheetIndex'] == 0xFFFF) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
6171
						throw new Exception('Deleted sheet reference');
6172
					}
6173
6174
					// we have normal sheet range (collapsed or uncollapsed)
6175
					$firstSheetName = $this->_sheets[$this->_ref[$index]['firstSheetIndex']]['name'];
6176
					$lastSheetName = $this->_sheets[$this->_ref[$index]['lastSheetIndex']]['name'];
6177
6178
					if ($firstSheetName == $lastSheetName) {
6179
						// collapsed sheet range
6180
						$sheetRange = $firstSheetName;
6181
					} else {
6182
						$sheetRange = "$firstSheetName:$lastSheetName";
6183
					}
6184
6185
					// escape the single-quotes
6186
					$sheetRange = str_replace("'", "''", $sheetRange);
6187
6188
					// if there are special characters, we need to enclose the range in single-quotes
6189
					// todo: check if we have identified the whole set of special characters
6190
					// it seems that the following characters are not accepted for sheet names
6191
					// and we may assume that they are not present: []*/:\?
6192
					if (preg_match("/[ !\"@#£$%&{()}<>=+'|^,;-]/", $sheetRange)) {
6193
						$sheetRange = "'$sheetRange'";
6194
					}
6195
6196
					return $sheetRange;
6197
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
6198
6199
				default:
6200
					// TODO: external sheet support
6201
					throw new Exception('Excel5 reader only supports internal sheets in fomulas');
6202
					break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
6203
			}
6204
		}
6205
		return false;
6206
	}
6207
6208
6209
	/**
6210
	 * read BIFF8 constant value array from array data
6211
	 * returns e.g. array('value' => '{1,2;3,4}', 'size' => 40}
6212
	 * section 2.5.8
6213
	 *
6214
	 * @param string $arrayData
6215
	 * @return array
6216
	 */
6217
	private static function _readBIFF8ConstantArray($arrayData)
6218
	{
6219
		// offset: 0; size: 1; number of columns decreased by 1
6220
		$nc = ord($arrayData[0]);
6221
6222
		// offset: 1; size: 2; number of rows decreased by 1
6223
		$nr = self::_GetInt2d($arrayData, 1);
6224
		$size = 3; // initialize
6225
		$arrayData = substr($arrayData, 3);
6226
6227
		// offset: 3; size: var; list of ($nc + 1) * ($nr + 1) constant values
6228
		$matrixChunks = array();
6229
		for ($r = 1; $r <= $nr + 1; ++$r) {
6230
			$items = array();
6231
			for ($c = 1; $c <= $nc + 1; ++$c) {
6232
				$constant = self::_readBIFF8Constant($arrayData);
6233
				$items[] = $constant['value'];
6234
				$arrayData = substr($arrayData, $constant['size']);
6235
				$size += $constant['size'];
6236
			}
6237
			$matrixChunks[] = implode(',', $items); // looks like e.g. '1,"hello"'
6238
		}
6239
		$matrix = '{' . implode(';', $matrixChunks) . '}';
6240
6241
		return array(
6242
			'value' => $matrix,
6243
			'size' => $size,
6244
		);
6245
	}
6246
6247
6248
	/**
6249
	 * read BIFF8 constant value which may be 'Empty Value', 'Number', 'String Value', 'Boolean Value', 'Error Value'
6250
	 * section 2.5.7
6251
	 * returns e.g. array('value' => '5', 'size' => 9)
6252
	 *
6253
	 * @param string $valueData
6254
	 * @return array
6255
	 */
6256
	private static function _readBIFF8Constant($valueData)
6257
	{
6258
		// offset: 0; size: 1; identifier for type of constant
6259
		$identifier = ord($valueData[0]);
6260
6261
		switch ($identifier) {
6262
		case 0x00: // empty constant (what is this?)
6263
			$value = '';
6264
			$size = 9;
6265
			break;
6266
		case 0x01: // number
6267
			// offset: 1; size: 8; IEEE 754 floating-point value
6268
			$value = self::_extractNumber(substr($valueData, 1, 8));
6269
			$size = 9;
6270
			break;
6271
		case 0x02: // string value
6272
			// offset: 1; size: var; Unicode string, 16-bit string length
6273
			$string = self::_readUnicodeStringLong(substr($valueData, 1));
6274
			$value = '"' . $string['value'] . '"';
6275
			$size = 1 + $string['size'];
6276
			break;
6277
		case 0x04: // boolean
6278
			// offset: 1; size: 1; 0 = FALSE, 1 = TRUE
6279
			if (ord($valueData[1])) {
6280
				$value = 'TRUE';
6281
			} else {
6282
				$value = 'FALSE';
6283
			}
6284
			$size = 9;
6285
			break;
6286
		case 0x10: // error code
6287
			// offset: 1; size: 1; error code
6288
			$value = self::_mapErrorCode(ord($valueData[1]));
6289
			$size = 9;
6290
			break;
6291
		}
6292
		return array(
6293
			'value' => $value,
0 ignored issues
show
Bug introduced by
The variable $value does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
6294
			'size' => $size,
0 ignored issues
show
Bug introduced by
The variable $size does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
6295
		);
6296
	}
6297
6298
6299
	/**
6300
	 * Extract RGB color
6301
	 * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.4
6302
	 *
6303
	 * @param string $rgb Encoded RGB value (4 bytes)
6304
	 * @return array
6305
	 */
6306
	private static function _readRGB($rgb)
6307
	{
6308
		// offset: 0; size 1; Red component
6309
		$r = ord($rgb{0});
6310
6311
		// offset: 1; size: 1; Green component
6312
		$g = ord($rgb{1});
6313
6314
		// offset: 2; size: 1; Blue component
6315
		$b = ord($rgb{2});
6316
6317
		// HEX notation, e.g. 'FF00FC'
6318
		$rgb = sprintf('%02X%02X%02X', $r, $g, $b);
6319
6320
		return array('rgb' => $rgb);
6321
	}
6322
6323
6324
	/**
6325
	 * Read byte string (8-bit string length)
6326
	 * OpenOffice documentation: 2.5.2
6327
	 *
6328
	 * @param string $subData
6329
	 * @return array
6330
	 */
6331 View Code Duplication
	private function _readByteStringShort($subData)
6332
	{
6333
		// offset: 0; size: 1; length of the string (character count)
6334
		$ln = ord($subData[0]);
6335
6336
		// offset: 1: size: var; character array (8-bit characters)
6337
		$value = $this->_decodeCodepage(substr($subData, 1, $ln));
6338
6339
		return array(
6340
			'value' => $value,
6341
			'size' => 1 + $ln, // size in bytes of data structure
6342
		);
6343
	}
6344
6345
6346
	/**
6347
	 * Read byte string (16-bit string length)
6348
	 * OpenOffice documentation: 2.5.2
6349
	 *
6350
	 * @param string $subData
6351
	 * @return array
6352
	 */
6353 View Code Duplication
	private function _readByteStringLong($subData)
6354
	{
6355
		// offset: 0; size: 2; length of the string (character count)
6356
		$ln = self::_GetInt2d($subData, 0);
6357
6358
		// offset: 2: size: var; character array (8-bit characters)
6359
		$value = $this->_decodeCodepage(substr($subData, 2));
6360
6361
		//return $string;
6362
		return array(
6363
			'value' => $value,
6364
			'size' => 2 + $ln, // size in bytes of data structure
6365
		);
6366
	}
6367
6368
6369
	/**
6370
	 * Extracts an Excel Unicode short string (8-bit string length)
6371
	 * OpenOffice documentation: 2.5.3
6372
	 * function will automatically find out where the Unicode string ends.
6373
	 *
6374
	 * @param string $subData
6375
	 * @return array
6376
	 */
6377 View Code Duplication
	private static function _readUnicodeStringShort($subData)
6378
	{
6379
		$value = '';
6380
6381
		// offset: 0: size: 1; length of the string (character count)
6382
		$characterCount = ord($subData[0]);
6383
6384
		$string = self::_readUnicodeString(substr($subData, 1), $characterCount);
6385
6386
		// add 1 for the string length
6387
		$string['size'] += 1;
6388
6389
		return $string;
6390
	}
6391
6392
6393
	/**
6394
	 * Extracts an Excel Unicode long string (16-bit string length)
6395
	 * OpenOffice documentation: 2.5.3
6396
	 * this function is under construction, needs to support rich text, and Asian phonetic settings
6397
	 *
6398
	 * @param string $subData
6399
	 * @return array
6400
	 */
6401 View Code Duplication
	private static function _readUnicodeStringLong($subData)
6402
	{
6403
		$value = '';
6404
6405
		// offset: 0: size: 2; length of the string (character count)
6406
		$characterCount = self::_GetInt2d($subData, 0);
6407
6408
		$string = self::_readUnicodeString(substr($subData, 2), $characterCount);
6409
6410
		// add 2 for the string length
6411
		$string['size'] += 2;
6412
6413
		return $string;
6414
	}
6415
6416
6417
	/**
6418
	 * Read Unicode string with no string length field, but with known character count
6419
	 * this function is under construction, needs to support rich text, and Asian phonetic settings
6420
	 * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.3
6421
	 *
6422
	 * @param string $subData
6423
	 * @param int $characterCount
6424
	 * @return array
6425
	 */
6426
	private static function _readUnicodeString($subData, $characterCount)
6427
	{
6428
		$value = '';
6429
6430
		// offset: 0: size: 1; option flags
6431
6432
			// bit: 0; mask: 0x01; character compression (0 = compressed 8-bit, 1 = uncompressed 16-bit)
6433
			$isCompressed = !((0x01 & ord($subData[0])) >> 0);
6434
6435
			// bit: 2; mask: 0x04; Asian phonetic settings
6436
			$hasAsian = (0x04) & ord($subData[0]) >> 2;
6437
6438
			// bit: 3; mask: 0x08; Rich-Text settings
6439
			$hasRichText = (0x08) & ord($subData[0]) >> 3;
6440
6441
		// offset: 1: size: var; character array
6442
		// this offset assumes richtext and Asian phonetic settings are off which is generally wrong
6443
		// needs to be fixed
6444
		$value = self::_encodeUTF16(substr($subData, 1, $isCompressed ? $characterCount : 2 * $characterCount), $isCompressed);
6445
6446
		return array(
6447
			'value' => $value,
6448
			'size' => $isCompressed ? 1 + $characterCount : 1 + 2 * $characterCount, // the size in bytes including the option flags
6449
		);
6450
	}
6451
6452
6453
	/**
6454
	 * Convert UTF-8 string to string surounded by double quotes. Used for explicit string tokens in formulas.
6455
	 * Example:  hello"world  -->  "hello""world"
6456
	 *
6457
	 * @param string $value UTF-8 encoded string
6458
	 * @return string
6459
	 */
6460
	private static function _UTF8toExcelDoubleQuoted($value)
6461
	{
6462
		return '"' . str_replace('"', '""', $value) . '"';
6463
	}
6464
6465
6466
	/**
6467
	 * Reads first 8 bytes of a string and return IEEE 754 float
6468
	 *
6469
	 * @param string $data Binary string that is at least 8 bytes long
6470
	 * @return float
6471
	 */
6472
	private static function _extractNumber($data)
6473
	{
6474
		$rknumhigh = self::_GetInt4d($data, 4);
6475
		$rknumlow = self::_GetInt4d($data, 0);
6476
		$sign = ($rknumhigh & 0x80000000) >> 31;
6477
		$exp = (($rknumhigh & 0x7ff00000) >> 20) - 1023;
6478
		$mantissa = (0x100000 | ($rknumhigh & 0x000fffff));
6479
		$mantissalow1 = ($rknumlow & 0x80000000) >> 31;
6480
		$mantissalow2 = ($rknumlow & 0x7fffffff);
6481
		$value = $mantissa / pow( 2 , (20 - $exp));
6482
6483
		if ($mantissalow1 != 0) {
6484
			$value += 1 / pow (2 , (21 - $exp));
6485
		}
6486
6487
		$value += $mantissalow2 / pow (2 , (52 - $exp));
6488
		if ($sign) {
6489
			$value *= -1;
6490
		}
6491
6492
		return $value;
6493
	}
6494
6495
6496
	private static function _GetIEEE754($rknum)
6497
	{
6498
		if (($rknum & 0x02) != 0) {
6499
			$value = $rknum >> 2;
6500
		} else {
6501
			// changes by mmp, info on IEEE754 encoding from
6502
			// research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
6503
			// The RK format calls for using only the most significant 30 bits
6504
			// of the 64 bit floating point value. The other 34 bits are assumed
6505
			// to be 0 so we use the upper 30 bits of $rknum as follows...
6506
			$sign = ($rknum & 0x80000000) >> 31;
6507
			$exp = ($rknum & 0x7ff00000) >> 20;
6508
			$mantissa = (0x100000 | ($rknum & 0x000ffffc));
6509
			$value = $mantissa / pow( 2 , (20- ($exp - 1023)));
6510
			if ($sign) {
6511
				$value = -1 * $value;
6512
			}
6513
			//end of changes by mmp
6514
		}
6515
		if (($rknum & 0x01) != 0) {
6516
			$value /= 100;
6517
		}
6518
		return $value;
6519
	}
6520
6521
6522
	/**
6523
	 * Get UTF-8 string from (compressed or uncompressed) UTF-16 string
6524
	 *
6525
	 * @param string $string
6526
	 * @param bool $compressed
6527
	 * @return string
6528
	 */
6529
	private static function _encodeUTF16($string, $compressed = '')
6530
	{
6531
		if ($compressed) {
6532
			$string = self::_uncompressByteString($string);
6533
 		}
6534
6535
		return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', 'UTF-16LE');
6536
	}
6537
6538
6539
	/**
6540
	 * Convert UTF-16 string in compressed notation to uncompressed form. Only used for BIFF8.
6541
	 *
6542
	 * @param string $string
6543
	 * @return string
6544
	 */
6545
	private static function _uncompressByteString($string)
6546
	{
6547
		$uncompressedString = '';
6548
		$strLen = strlen($string);
6549
		for ($i = 0; $i < $strLen; ++$i) {
6550
			$uncompressedString .= $string[$i] . "\0";
6551
		}
6552
6553
		return $uncompressedString;
6554
	}
6555
6556
6557
	/**
6558
	 * Convert string to UTF-8. Only used for BIFF5.
6559
	 *
6560
	 * @param string $string
6561
	 * @return string
6562
	 */
6563
	private function _decodeCodepage($string)
6564
	{
6565
		return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', $this->_codepage);
6566
	}
6567
6568
6569
	/**
6570
	 * Read 16-bit unsigned integer
6571
	 *
6572
	 * @param string $data
6573
	 * @param int $pos
6574
	 * @return int
6575
	 */
6576
	public static function _GetInt2d($data, $pos)
6577
	{
6578
		return ord($data[$pos]) | (ord($data[$pos+1]) << 8);
6579
	}
6580
6581
6582
	/**
6583
	 * Read 32-bit signed integer
6584
	 *
6585
	 * @param string $data
6586
	 * @param int $pos
6587
	 * @return int
6588
	 */
6589 View Code Duplication
	public static function _GetInt4d($data, $pos)
6590
	{
6591
		// FIX: represent numbers correctly on 64-bit system
6592
		// http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
6593
		// Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
6594
		$_or_24 = ord($data[$pos + 3]);
6595
		if ($_or_24 >= 128) {
6596
			// negative number
6597
			$_ord_24 = -abs((256 - $_or_24) << 24);
6598
		} else {
6599
			$_ord_24 = ($_or_24 & 127) << 24;
6600
		}
6601
		return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $_ord_24;
6602
	}
6603
6604
6605
	/**
6606
	 * Read color
6607
	 *
6608
	 * @param int $color Indexed color
6609
	 * @param array $palette Color palette
6610
	 * @return array RGB color value, example: array('rgb' => 'FF0000')
6611
	 */
6612
	private static function _readColor($color,$palette,$version)
6613
	{
6614
		if ($color <= 0x07 || $color >= 0x40) {
6615
			// special built-in color
6616
			return self::_mapBuiltInColor($color);
6617
		} elseif (isset($palette) && isset($palette[$color - 8])) {
6618
			// palette color, color index 0x08 maps to pallete index 0
6619
			return $palette[$color - 8];
6620
		} else {
6621
			// default color table
6622
			if ($version == self::XLS_BIFF8) {
6623
				return self::_mapColor($color);
6624
			} else {
6625
				// BIFF5
6626
				return self::_mapColorBIFF5($color);
6627
			}
6628
		}
6629
6630
		return $color;
0 ignored issues
show
Unused Code introduced by
return $color; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
6631
	}
6632
6633
6634
	/**
6635
	 * Map border style
6636
	 * OpenOffice documentation: 2.5.11
6637
	 *
6638
	 * @param int $index
6639
	 * @return string
6640
	 */
6641 View Code Duplication
	private static function _mapBorderStyle($index)
6642
	{
6643
		switch ($index) {
6644
			case 0x00: return PHPExcel_Style_Border::BORDER_NONE;
6645
			case 0x01: return PHPExcel_Style_Border::BORDER_THIN;
6646
			case 0x02: return PHPExcel_Style_Border::BORDER_MEDIUM;
6647
			case 0x03: return PHPExcel_Style_Border::BORDER_DASHED;
6648
			case 0x04: return PHPExcel_Style_Border::BORDER_DOTTED;
6649
			case 0x05: return PHPExcel_Style_Border::BORDER_THICK;
6650
			case 0x06: return PHPExcel_Style_Border::BORDER_DOUBLE;
6651
			case 0x07: return PHPExcel_Style_Border::BORDER_HAIR;
6652
			case 0x08: return PHPExcel_Style_Border::BORDER_MEDIUMDASHED;
6653
			case 0x09: return PHPExcel_Style_Border::BORDER_DASHDOT;
6654
			case 0x0A: return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT;
6655
			case 0x0B: return PHPExcel_Style_Border::BORDER_DASHDOTDOT;
6656
			case 0x0C: return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT;
6657
			case 0x0D: return PHPExcel_Style_Border::BORDER_SLANTDASHDOT;
6658
			default:   return PHPExcel_Style_Border::BORDER_NONE;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
6659
		}
6660
	}
6661
6662
6663
	/**
6664
	 * Get fill pattern from index
6665
	 * OpenOffice documentation: 2.5.12
6666
	 *
6667
	 * @param int $index
6668
	 * @return string
6669
	 */
6670
	private static function _mapFillPattern($index)
6671
	{
6672
		switch ($index) {
6673
			case 0x00: return PHPExcel_Style_Fill::FILL_NONE;
6674
			case 0x01: return PHPExcel_Style_Fill::FILL_SOLID;
6675
			case 0x02: return PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY;
6676
			case 0x03: return PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY;
6677
			case 0x04: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY;
6678
			case 0x05: return PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL;
6679
			case 0x06: return PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL;
6680
			case 0x07: return PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN;
6681
			case 0x08: return PHPExcel_Style_Fill::FILL_PATTERN_DARKUP;
6682
			case 0x09: return PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID;
6683
			case 0x0A: return PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS;
6684
			case 0x0B: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL;
6685
			case 0x0C: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL;
6686
			case 0x0D: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN;
6687
			case 0x0E: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP;
6688
			case 0x0F: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID;
6689
			case 0x10: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS;
6690
			case 0x11: return PHPExcel_Style_Fill::FILL_PATTERN_GRAY125;
6691
			case 0x12: return PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625;
6692
			default:   return PHPExcel_Style_Fill::FILL_NONE;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
6693
		}
6694
	}
6695
6696
6697
	/**
6698
	 * Map error code, e.g. '#N/A'
6699
	 *
6700
	 * @param int $subData
6701
	 * @return string
6702
	 */
6703
	private static function _mapErrorCode($subData)
6704
	{
6705
		switch ($subData) {
6706
			case 0x00: return '#NULL!';		break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
6707
			case 0x07: return '#DIV/0!';	break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
6708
			case 0x0F: return '#VALUE!';	break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
6709
			case 0x17: return '#REF!';		break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
6710
			case 0x1D: return '#NAME?';		break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
6711
			case 0x24: return '#NUM!';		break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
6712
			case 0x2A: return '#N/A';		break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
6713
			default: return false;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
6714
		}
6715
	}
6716
6717
6718
	/**
6719
	 * Map built-in color to RGB value
6720
	 *
6721
	 * @param int $color Indexed color
6722
	 * @return array
6723
	 */
6724
	private static function _mapBuiltInColor($color)
6725
	{
6726
		switch ($color) {
6727
			case 0x00: return array('rgb' => '000000');
6728
			case 0x01: return array('rgb' => 'FFFFFF');
6729
			case 0x02: return array('rgb' => 'FF0000');
6730
			case 0x03: return array('rgb' => '00FF00');
6731
			case 0x04: return array('rgb' => '0000FF');
6732
			case 0x05: return array('rgb' => 'FFFF00');
6733
			case 0x06: return array('rgb' => 'FF00FF');
6734
			case 0x07: return array('rgb' => '00FFFF');
6735
			case 0x40: return array('rgb' => '000000'); // system window text color
6736
			case 0x41: return array('rgb' => 'FFFFFF'); // system window background color
6737
			default:   return array('rgb' => '000000');
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
6738
		}
6739
	}
6740
6741
6742
	/**
6743
	 * Map color array from BIFF5 built-in color index
6744
	 *
6745
	 * @param int $subData
6746
	 * @return array
6747
	 */
6748
	private static function _mapColorBIFF5($subData)
6749
	{
6750
		switch ($subData) {
6751
			case 0x08: return array('rgb' => '000000');
6752
			case 0x09: return array('rgb' => 'FFFFFF');
6753
			case 0x0A: return array('rgb' => 'FF0000');
6754
			case 0x0B: return array('rgb' => '00FF00');
6755
			case 0x0C: return array('rgb' => '0000FF');
6756
			case 0x0D: return array('rgb' => 'FFFF00');
6757
			case 0x0E: return array('rgb' => 'FF00FF');
6758
			case 0x0F: return array('rgb' => '00FFFF');
6759
			case 0x10: return array('rgb' => '800000');
6760
			case 0x11: return array('rgb' => '008000');
6761
			case 0x12: return array('rgb' => '000080');
6762
			case 0x13: return array('rgb' => '808000');
6763
			case 0x14: return array('rgb' => '800080');
6764
			case 0x15: return array('rgb' => '008080');
6765
			case 0x16: return array('rgb' => 'C0C0C0');
6766
			case 0x17: return array('rgb' => '808080');
6767
			case 0x18: return array('rgb' => '8080FF');
6768
			case 0x19: return array('rgb' => '802060');
6769
			case 0x1A: return array('rgb' => 'FFFFC0');
6770
			case 0x1B: return array('rgb' => 'A0E0F0');
6771
			case 0x1C: return array('rgb' => '600080');
6772
			case 0x1D: return array('rgb' => 'FF8080');
6773
			case 0x1E: return array('rgb' => '0080C0');
6774
			case 0x1F: return array('rgb' => 'C0C0FF');
6775
			case 0x20: return array('rgb' => '000080');
6776
			case 0x21: return array('rgb' => 'FF00FF');
6777
			case 0x22: return array('rgb' => 'FFFF00');
6778
			case 0x23: return array('rgb' => '00FFFF');
6779
			case 0x24: return array('rgb' => '800080');
6780
			case 0x25: return array('rgb' => '800000');
6781
			case 0x26: return array('rgb' => '008080');
6782
			case 0x27: return array('rgb' => '0000FF');
6783
			case 0x28: return array('rgb' => '00CFFF');
6784
			case 0x29: return array('rgb' => '69FFFF');
6785
			case 0x2A: return array('rgb' => 'E0FFE0');
6786
			case 0x2B: return array('rgb' => 'FFFF80');
6787
			case 0x2C: return array('rgb' => 'A6CAF0');
6788
			case 0x2D: return array('rgb' => 'DD9CB3');
6789
			case 0x2E: return array('rgb' => 'B38FEE');
6790
			case 0x2F: return array('rgb' => 'E3E3E3');
6791
			case 0x30: return array('rgb' => '2A6FF9');
6792
			case 0x31: return array('rgb' => '3FB8CD');
6793
			case 0x32: return array('rgb' => '488436');
6794
			case 0x33: return array('rgb' => '958C41');
6795
			case 0x34: return array('rgb' => '8E5E42');
6796
			case 0x35: return array('rgb' => 'A0627A');
6797
			case 0x36: return array('rgb' => '624FAC');
6798
			case 0x37: return array('rgb' => '969696');
6799
			case 0x38: return array('rgb' => '1D2FBE');
6800
			case 0x39: return array('rgb' => '286676');
6801
			case 0x3A: return array('rgb' => '004500');
6802
			case 0x3B: return array('rgb' => '453E01');
6803
			case 0x3C: return array('rgb' => '6A2813');
6804
			case 0x3D: return array('rgb' => '85396A');
6805
			case 0x3E: return array('rgb' => '4A3285');
6806
			case 0x3F: return array('rgb' => '424242');
6807
			default:   return array('rgb' => '000000');
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
6808
		}
6809
	}
6810
6811
6812
	/**
6813
	 * Map color array from BIFF8 built-in color index
6814
	 *
6815
	 * @param int $subData
6816
	 * @return array
6817
	 */
6818
	private static function _mapColor($subData)
6819
	{
6820
		switch ($subData) {
6821
			case 0x08: return array('rgb' => '000000');
6822
			case 0x09: return array('rgb' => 'FFFFFF');
6823
			case 0x0A: return array('rgb' => 'FF0000');
6824
			case 0x0B: return array('rgb' => '00FF00');
6825
			case 0x0C: return array('rgb' => '0000FF');
6826
			case 0x0D: return array('rgb' => 'FFFF00');
6827
			case 0x0E: return array('rgb' => 'FF00FF');
6828
			case 0x0F: return array('rgb' => '00FFFF');
6829
			case 0x10: return array('rgb' => '800000');
6830
			case 0x11: return array('rgb' => '008000');
6831
			case 0x12: return array('rgb' => '000080');
6832
			case 0x13: return array('rgb' => '808000');
6833
			case 0x14: return array('rgb' => '800080');
6834
			case 0x15: return array('rgb' => '008080');
6835
			case 0x16: return array('rgb' => 'C0C0C0');
6836
			case 0x17: return array('rgb' => '808080');
6837
			case 0x18: return array('rgb' => '9999FF');
6838
			case 0x19: return array('rgb' => '993366');
6839
			case 0x1A: return array('rgb' => 'FFFFCC');
6840
			case 0x1B: return array('rgb' => 'CCFFFF');
6841
			case 0x1C: return array('rgb' => '660066');
6842
			case 0x1D: return array('rgb' => 'FF8080');
6843
			case 0x1E: return array('rgb' => '0066CC');
6844
			case 0x1F: return array('rgb' => 'CCCCFF');
6845
			case 0x20: return array('rgb' => '000080');
6846
			case 0x21: return array('rgb' => 'FF00FF');
6847
			case 0x22: return array('rgb' => 'FFFF00');
6848
			case 0x23: return array('rgb' => '00FFFF');
6849
			case 0x24: return array('rgb' => '800080');
6850
			case 0x25: return array('rgb' => '800000');
6851
			case 0x26: return array('rgb' => '008080');
6852
			case 0x27: return array('rgb' => '0000FF');
6853
			case 0x28: return array('rgb' => '00CCFF');
6854
			case 0x29: return array('rgb' => 'CCFFFF');
6855
			case 0x2A: return array('rgb' => 'CCFFCC');
6856
			case 0x2B: return array('rgb' => 'FFFF99');
6857
			case 0x2C: return array('rgb' => '99CCFF');
6858
			case 0x2D: return array('rgb' => 'FF99CC');
6859
			case 0x2E: return array('rgb' => 'CC99FF');
6860
			case 0x2F: return array('rgb' => 'FFCC99');
6861
			case 0x30: return array('rgb' => '3366FF');
6862
			case 0x31: return array('rgb' => '33CCCC');
6863
			case 0x32: return array('rgb' => '99CC00');
6864
			case 0x33: return array('rgb' => 'FFCC00');
6865
			case 0x34: return array('rgb' => 'FF9900');
6866
			case 0x35: return array('rgb' => 'FF6600');
6867
			case 0x36: return array('rgb' => '666699');
6868
			case 0x37: return array('rgb' => '969696');
6869
			case 0x38: return array('rgb' => '003366');
6870
			case 0x39: return array('rgb' => '339966');
6871
			case 0x3A: return array('rgb' => '003300');
6872
			case 0x3B: return array('rgb' => '333300');
6873
			case 0x3C: return array('rgb' => '993300');
6874
			case 0x3D: return array('rgb' => '993366');
6875
			case 0x3E: return array('rgb' => '333399');
6876
			case 0x3F: return array('rgb' => '333333');
6877
			default:   return array('rgb' => '000000');
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
6878
		}
6879
	}
6880
6881
6882
	private function _parseRichText($is = '') {
6883
		$value = new PHPExcel_RichText();
6884
6885
		$value->createText($is);
6886
6887
		return $value;
6888
	}
6889
6890
}
6891