PHPExcel_Calculation::parseFormula()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 6
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 11
rs 9.2
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_Calculation
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
29
/** PHPExcel root directory */
30 View Code Duplication
if (!defined('PHPEXCEL_ROOT')) {
31
	/**
32
	 * @ignore
33
	 */
34
	define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../');
35
	require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
36
}
37
38
39
if (!defined('CALCULATION_REGEXP_CELLREF')) {
40
	//	Test for support of \P (multibyte options) in PCRE
41
	if(defined('PREG_BAD_UTF8_ERROR')) {
42
		//	Cell reference (cell or range of cells, with or without a sheet reference)
43
		define('CALCULATION_REGEXP_CELLREF','((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d{1,7})');
44
		//	Named Range of cells
45
		define('CALCULATION_REGEXP_NAMEDRANGE','((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?([_A-Z][_A-Z0-9\.]*)');
46
	} else {
47
		//	Cell reference (cell or range of cells, with or without a sheet reference)
48
		define('CALCULATION_REGEXP_CELLREF','(((\w*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d+)');
49
		//	Named Range of cells
50
		define('CALCULATION_REGEXP_NAMEDRANGE','(((\w*)|(\'.*\')|(\".*\"))!)?([_A-Z][_A-Z0-9\.]*)');
51
	}
52
}
53
54
55
/**
56
 * PHPExcel_Calculation (Singleton)
57
 *
58
 * @category	PHPExcel
59
 * @package		PHPExcel_Calculation
60
 * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
61
 */
62
class PHPExcel_Calculation {
63
64
	/** Constants				*/
65
	/** Regular Expressions		*/
66
	//	Numeric operand
67
	const CALCULATION_REGEXP_NUMBER		= '[-+]?\d*\.?\d+(e[-+]?\d+)?';
68
	//	String operand
69
	const CALCULATION_REGEXP_STRING		= '"(?:[^"]|"")*"';
70
	//	Opening bracket
71
	const CALCULATION_REGEXP_OPENBRACE	= '\(';
72
	//	Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it)
73
	const CALCULATION_REGEXP_FUNCTION	= '@?([A-Z][A-Z0-9\.]*)[\s]*\(';
74
	//	Cell reference (cell or range of cells, with or without a sheet reference)
75
	const CALCULATION_REGEXP_CELLREF	= CALCULATION_REGEXP_CELLREF;
76
	//	Named Range of cells
77
	const CALCULATION_REGEXP_NAMEDRANGE	= CALCULATION_REGEXP_NAMEDRANGE;
78
	//	Error
79
	const CALCULATION_REGEXP_ERROR		= '\#[A-Z][A-Z0_\/]*[!\?]?';
80
81
82
	/** constants */
83
	const RETURN_ARRAY_AS_ERROR = 'error';
84
	const RETURN_ARRAY_AS_VALUE = 'value';
85
	const RETURN_ARRAY_AS_ARRAY = 'array';
86
87
	private static $returnArrayAsType	= self::RETURN_ARRAY_AS_VALUE;
88
89
90
	/**
91
	 * Instance of this class
92
	 *
93
	 * @access	private
94
	 * @var PHPExcel_Calculation
95
	 */
96
	private static $_instance;
97
98
99
	/**
100
	 * Calculation cache
101
	 *
102
	 * @access	private
103
	 * @var array
104
	 */
105
	private static $_calculationCache = array ();
106
107
108
	/**
109
	 * Calculation cache enabled
110
	 *
111
	 * @access	private
112
	 * @var boolean
113
	 */
114
	private static $_calculationCacheEnabled = true;
115
116
117
	/**
118
	 * Calculation cache expiration time
119
	 *
120
	 * @access	private
121
	 * @var float
122
	 */
123
	private static $_calculationCacheExpirationTime = 15;
124
125
126
	/**
127
	 * List of operators that can be used within formulae
128
	 * The true/false value indicates whether it is a binary operator or a unary operator
129
	 *
130
	 * @access	private
131
	 * @var array
132
	 */
133
	private static $_operators			= array('+' => true,	'-' => true,	'*' => true,	'/' => true,
134
												'^' => true,	'&' => true,	'%' => false,	'~' => false,
135
												'>' => true,	'<' => true,	'=' => true,	'>=' => true,
136
												'<=' => true,	'<>' => true,	'|' => true,	':' => true
137
											   );
138
139
140
	/**
141
	 * List of binary operators (those that expect two operands)
142
	 *
143
	 * @access	private
144
	 * @var array
145
	 */
146
	private static $_binaryOperators	= array('+' => true,	'-' => true,	'*' => true,	'/' => true,
147
												'^' => true,	'&' => true,	'>' => true,	'<' => true,
148
												'=' => true,	'>=' => true,	'<=' => true,	'<>' => true,
149
												'|' => true,	':' => true
150
											   );
151
152
	/**
153
	 * Flag to determine how formula errors should be handled
154
	 *		If true, then a user error will be triggered
155
	 *		If false, then an exception will be thrown
156
	 *
157
	 * @access	public
158
	 * @var boolean
159
	 *
160
	 */
161
	public $suppressFormulaErrors = false;
162
163
	/**
164
	 * Error message for any error that was raised/thrown by the calculation engine
165
	 *
166
	 * @access	public
167
	 * @var string
168
	 *
169
	 */
170
	public $formulaError = null;
171
172
	/**
173
	 * Flag to determine whether a debug log should be generated by the calculation engine
174
	 *		If true, then a debug log will be generated
175
	 *		If false, then a debug log will not be generated
176
	 *
177
	 * @access	public
178
	 * @var boolean
179
	 *
180
	 */
181
	public $writeDebugLog = false;
182
183
	/**
184
	 * Flag to determine whether a debug log should be echoed by the calculation engine
185
	 *		If true, then a debug log will be echoed
186
	 *		If false, then a debug log will not be echoed
187
	 * A debug log can only be echoed if it is generated
188
	 *
189
	 * @access	public
190
	 * @var boolean
191
	 *
192
	 */
193
	public $echoDebugLog = false;
194
195
196
	/**
197
	 * An array of the nested cell references accessed by the calculation engine, used for the debug log
198
	 *
199
	 * @access	private
200
	 * @var array of string
201
	 *
202
	 */
203
	private $debugLogStack = array();
204
205
	/**
206
	 * The debug log generated by the calculation engine
207
	 *
208
	 * @access	public
209
	 * @var array of string
210
	 *
211
	 */
212
	public $debugLog = array();
213
	private $_cyclicFormulaCount = 0;
214
	private $_cyclicFormulaCell = '';
215
	public $cyclicFormulaCount = 0;
216
217
218
	private $_savedPrecision	= 12;
219
220
221
	private static $_localeLanguage = 'en_us';					//	US English	(default locale)
222
	private static $_validLocaleLanguages = array(	'en'		//	English		(default language)
223
												 );
224
	private static $_localeArgumentSeparator = ',';
225
	private static $_localeFunctions = array();
226
	public static $_localeBoolean = array(	'TRUE'	=> 'TRUE',
227
											'FALSE'	=> 'FALSE',
228
											'NULL'	=> 'NULL'
229
										  );
230
231
232
	//	Constant conversion from text name/value to actual (datatyped) value
233
	private static $_ExcelConstants = array('TRUE'	=> true,
234
											'FALSE'	=> false,
235
											'NULL'	=> null
236
										   );
237
238
	//	PHPExcel functions
239
	private static $_PHPExcelFunctions = array(	// PHPExcel functions
240
				'ABS'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
241
												 'functionCall'		=>	'abs',
242
												 'argumentCount'	=>	'1'
243
												),
244
				'ACCRINT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
245
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::ACCRINT',
246
												 'argumentCount'	=>	'4-7'
247
												),
248
				'ACCRINTM'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
249
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::ACCRINTM',
250
												 'argumentCount'	=>	'3-5'
251
												),
252
				'ACOS'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
253
												 'functionCall'		=>	'acos',
254
												 'argumentCount'	=>	'1'
255
												),
256
				'ACOSH'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
257
												 'functionCall'		=>	'acosh',
258
												 'argumentCount'	=>	'1'
259
												),
260
				'ADDRESS'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
261
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::CELL_ADDRESS',
262
												 'argumentCount'	=>	'2-5'
263
												),
264
				'AMORDEGRC'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
265
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::AMORDEGRC',
266
												 'argumentCount'	=>	'6,7'
267
												),
268
				'AMORLINC'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
269
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::AMORLINC',
270
												 'argumentCount'	=>	'6,7'
271
												),
272
				'AND'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
273
												 'functionCall'		=>	'PHPExcel_Calculation_Logical::LOGICAL_AND',
274
												 'argumentCount'	=>	'1+'
275
												),
276
				'AREAS'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
277
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
278
												 'argumentCount'	=>	'1'
279
												),
280
				'ASC'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
281
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
282
												 'argumentCount'	=>	'1'
283
												),
284
				'ASIN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
285
												 'functionCall'		=>	'asin',
286
												 'argumentCount'	=>	'1'
287
												),
288
				'ASINH'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
289
												 'functionCall'		=>	'asinh',
290
												 'argumentCount'	=>	'1'
291
												),
292
				'ATAN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
293
												 'functionCall'		=>	'atan',
294
												 'argumentCount'	=>	'1'
295
												),
296
				'ATAN2'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
297
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::ATAN2',
298
												 'argumentCount'	=>	'2'
299
												),
300
				'ATANH'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
301
												 'functionCall'		=>	'atanh',
302
												 'argumentCount'	=>	'1'
303
												),
304
				'AVEDEV'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
305
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::AVEDEV',
306
												 'argumentCount'	=>	'1+'
307
												),
308
				'AVERAGE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
309
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::AVERAGE',
310
												 'argumentCount'	=>	'1+'
311
												),
312
				'AVERAGEA'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
313
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::AVERAGEA',
314
												 'argumentCount'	=>	'1+'
315
												),
316
				'AVERAGEIF'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
317
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::AVERAGEIF',
318
												 'argumentCount'	=>	'2,3'
319
												),
320
				'AVERAGEIFS'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
321
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
322
												 'argumentCount'	=>	'3+'
323
												),
324
				'BAHTTEXT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
325
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
326
												 'argumentCount'	=>	'1'
327
												),
328
				'BESSELI'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
329
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::BESSELI',
330
												 'argumentCount'	=>	'2'
331
												),
332
				'BESSELJ'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
333
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::BESSELJ',
334
												 'argumentCount'	=>	'2'
335
												),
336
				'BESSELK'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
337
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::BESSELK',
338
												 'argumentCount'	=>	'2'
339
												),
340
				'BESSELY'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
341
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::BESSELY',
342
												 'argumentCount'	=>	'2'
343
												),
344
				'BETADIST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
345
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::BETADIST',
346
												 'argumentCount'	=>	'3-5'
347
												),
348
				'BETAINV'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
349
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::BETAINV',
350
												 'argumentCount'	=>	'3-5'
351
												),
352
				'BIN2DEC'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
353
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::BINTODEC',
354
												 'argumentCount'	=>	'1'
355
												),
356
				'BIN2HEX'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
357
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::BINTOHEX',
358
												 'argumentCount'	=>	'1,2'
359
												),
360
				'BIN2OCT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
361
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::BINTOOCT',
362
												 'argumentCount'	=>	'1,2'
363
												),
364
				'BINOMDIST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
365
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::BINOMDIST',
366
												 'argumentCount'	=>	'4'
367
												),
368
				'CEILING'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
369
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::CEILING',
370
												 'argumentCount'	=>	'2'
371
												),
372
				'CELL'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
373
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
374
												 'argumentCount'	=>	'1,2'
375
												),
376
				'CHAR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
377
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::CHARACTER',
378
												 'argumentCount'	=>	'1'
379
												),
380
				'CHIDIST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
381
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::CHIDIST',
382
												 'argumentCount'	=>	'2'
383
												),
384
				'CHIINV'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
385
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::CHIINV',
386
												 'argumentCount'	=>	'2'
387
												),
388
				'CHITEST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
389
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
390
												 'argumentCount'	=>	'2'
391
												),
392
				'CHOOSE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
393
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::CHOOSE',
394
												 'argumentCount'	=>	'2+'
395
												),
396
				'CLEAN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
397
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::TRIMNONPRINTABLE',
398
												 'argumentCount'	=>	'1'
399
												),
400
				'CODE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
401
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::ASCIICODE',
402
												 'argumentCount'	=>	'1'
403
												),
404
				'COLUMN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
405
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::COLUMN',
406
												 'argumentCount'	=>	'-1',
407
												 'passByReference'	=>	array(true)
408
												),
409
				'COLUMNS'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
410
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::COLUMNS',
411
												 'argumentCount'	=>	'1'
412
												),
413
				'COMBIN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
414
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::COMBIN',
415
												 'argumentCount'	=>	'2'
416
												),
417
				'COMPLEX'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
418
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::COMPLEX',
419
												 'argumentCount'	=>	'2,3'
420
												),
421
				'CONCATENATE'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
422
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::CONCATENATE',
423
												 'argumentCount'	=>	'1+'
424
												),
425
				'CONFIDENCE'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
426
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::CONFIDENCE',
427
												 'argumentCount'	=>	'3'
428
												),
429
				'CONVERT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
430
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::CONVERTUOM',
431
												 'argumentCount'	=>	'3'
432
												),
433
				'CORREL'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
434
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::CORREL',
435
												 'argumentCount'	=>	'2'
436
												),
437
				'COS'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
438
												 'functionCall'		=>	'cos',
439
												 'argumentCount'	=>	'1'
440
												),
441
				'COSH'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
442
												 'functionCall'		=>	'cosh',
443
												 'argumentCount'	=>	'1'
444
												),
445
				'COUNT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
446
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::COUNT',
447
												 'argumentCount'	=>	'1+'
448
												),
449
				'COUNTA'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
450
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::COUNTA',
451
												 'argumentCount'	=>	'1+'
452
												),
453
				'COUNTBLANK'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
454
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::COUNTBLANK',
455
												 'argumentCount'	=>	'1'
456
												),
457
				'COUNTIF'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
458
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::COUNTIF',
459
												 'argumentCount'	=>	'2'
460
												),
461
				'COUNTIFS'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
462
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
463
												 'argumentCount'	=>	'2'
464
												),
465
				'COUPDAYBS'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
466
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::COUPDAYBS',
467
												 'argumentCount'	=>	'3,4'
468
												),
469
				'COUPDAYS'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
470
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::COUPDAYS',
471
												 'argumentCount'	=>	'3,4'
472
												),
473
				'COUPDAYSNC'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
474
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::COUPDAYSNC',
475
												 'argumentCount'	=>	'3,4'
476
												),
477
				'COUPNCD'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
478
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::COUPNCD',
479
												 'argumentCount'	=>	'3,4'
480
												),
481
				'COUPNUM'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
482
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::COUPNUM',
483
												 'argumentCount'	=>	'3,4'
484
												),
485
				'COUPPCD'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
486
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::COUPPCD',
487
												 'argumentCount'	=>	'3,4'
488
												),
489
				'COVAR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
490
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::COVAR',
491
												 'argumentCount'	=>	'2'
492
												),
493
				'CRITBINOM'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
494
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::CRITBINOM',
495
												 'argumentCount'	=>	'3'
496
												),
497
				'CUBEKPIMEMBER'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_CUBE,
498
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
499
												 'argumentCount'	=>	'?'
500
												),
501
				'CUBEMEMBER'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_CUBE,
502
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
503
												 'argumentCount'	=>	'?'
504
												),
505
				'CUBEMEMBERPROPERTY'	=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_CUBE,
506
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
507
												 'argumentCount'	=>	'?'
508
												),
509
				'CUBERANKEDMEMBER'		=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_CUBE,
510
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
511
												 'argumentCount'	=>	'?'
512
												),
513
				'CUBESET'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_CUBE,
514
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
515
												 'argumentCount'	=>	'?'
516
												),
517
				'CUBESETCOUNT'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_CUBE,
518
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
519
												 'argumentCount'	=>	'?'
520
												),
521
				'CUBEVALUE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_CUBE,
522
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
523
												 'argumentCount'	=>	'?'
524
												),
525
				'CUMIPMT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
526
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::CUMIPMT',
527
												 'argumentCount'	=>	'6'
528
												),
529
				'CUMPRINC'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
530
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::CUMPRINC',
531
												 'argumentCount'	=>	'6'
532
												),
533
				'DATE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
534
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::DATE',
535
												 'argumentCount'	=>	'3'
536
												),
537
				'DATEDIF'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
538
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::DATEDIF',
539
												 'argumentCount'	=>	'2,3'
540
												),
541
				'DATEVALUE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
542
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::DATEVALUE',
543
												 'argumentCount'	=>	'1'
544
												),
545
				'DAVERAGE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
546
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DAVERAGE',
547
												 'argumentCount'	=>	'3'
548
												),
549
				'DAY'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
550
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::DAYOFMONTH',
551
												 'argumentCount'	=>	'1'
552
												),
553
				'DAYS360'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
554
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::DAYS360',
555
												 'argumentCount'	=>	'2,3'
556
												),
557
				'DB'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
558
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::DB',
559
												 'argumentCount'	=>	'4,5'
560
												),
561
				'DCOUNT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
562
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DCOUNT',
563
												 'argumentCount'	=>	'3'
564
												),
565
				'DCOUNTA'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
566
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DCOUNTA',
567
												 'argumentCount'	=>	'3'
568
												),
569
				'DDB'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
570
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::DDB',
571
												 'argumentCount'	=>	'4,5'
572
												),
573
				'DEC2BIN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
574
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::DECTOBIN',
575
												 'argumentCount'	=>	'1,2'
576
												),
577
				'DEC2HEX'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
578
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::DECTOHEX',
579
												 'argumentCount'	=>	'1,2'
580
												),
581
				'DEC2OCT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
582
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::DECTOOCT',
583
												 'argumentCount'	=>	'1,2'
584
												),
585
				'DEGREES'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
586
												 'functionCall'		=>	'rad2deg',
587
												 'argumentCount'	=>	'1'
588
												),
589
				'DELTA'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
590
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::DELTA',
591
												 'argumentCount'	=>	'1,2'
592
												),
593
				'DEVSQ'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
594
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::DEVSQ',
595
												 'argumentCount'	=>	'1+'
596
												),
597
				'DGET'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
598
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DGET',
599
												 'argumentCount'	=>	'3'
600
												),
601
				'DISC'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
602
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::DISC',
603
												 'argumentCount'	=>	'4,5'
604
												),
605
				'DMAX'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
606
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DMAX',
607
												 'argumentCount'	=>	'3'
608
												),
609
				'DMIN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
610
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DMIN',
611
												 'argumentCount'	=>	'3'
612
												),
613
				'DOLLAR'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
614
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::DOLLAR',
615
												 'argumentCount'	=>	'1,2'
616
												),
617
				'DOLLARDE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
618
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::DOLLARDE',
619
												 'argumentCount'	=>	'2'
620
												),
621
				'DOLLARFR'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
622
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::DOLLARFR',
623
												 'argumentCount'	=>	'2'
624
												),
625
				'DPRODUCT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
626
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DPRODUCT',
627
												 'argumentCount'	=>	'3'
628
												),
629
				'DSTDEV'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
630
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DSTDEV',
631
												 'argumentCount'	=>	'3'
632
												),
633
				'DSTDEVP'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
634
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DSTDEVP',
635
												 'argumentCount'	=>	'3'
636
												),
637
				'DSUM'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
638
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DSUM',
639
												 'argumentCount'	=>	'3'
640
												),
641
				'DURATION'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
642
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
643
												 'argumentCount'	=>	'5,6'
644
												),
645
				'DVAR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
646
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DVAR',
647
												 'argumentCount'	=>	'3'
648
												),
649
				'DVARP'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATABASE,
650
												 'functionCall'		=>	'PHPExcel_Calculation_Database::DVARP',
651
												 'argumentCount'	=>	'3'
652
												),
653
				'EDATE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
654
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::EDATE',
655
												 'argumentCount'	=>	'2'
656
												),
657
				'EFFECT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
658
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::EFFECT',
659
												 'argumentCount'	=>	'2'
660
												),
661
				'EOMONTH'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
662
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::EOMONTH',
663
												 'argumentCount'	=>	'2'
664
												),
665
				'ERF'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
666
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::ERF',
667
												 'argumentCount'	=>	'1,2'
668
												),
669
				'ERFC'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
670
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::ERFC',
671
												 'argumentCount'	=>	'1'
672
												),
673
				'ERROR.TYPE'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
674
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::ERROR_TYPE',
675
												 'argumentCount'	=>	'1'
676
												),
677
				'EVEN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
678
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::EVEN',
679
												 'argumentCount'	=>	'1'
680
												),
681
				'EXACT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
682
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
683
												 'argumentCount'	=>	'2'
684
												),
685
				'EXP'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
686
												 'functionCall'		=>	'exp',
687
												 'argumentCount'	=>	'1'
688
												),
689
				'EXPONDIST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
690
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::EXPONDIST',
691
												 'argumentCount'	=>	'3'
692
												),
693
				'FACT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
694
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::FACT',
695
												 'argumentCount'	=>	'1'
696
												),
697
				'FACTDOUBLE'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
698
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::FACTDOUBLE',
699
												 'argumentCount'	=>	'1'
700
												),
701
				'FALSE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
702
												 'functionCall'		=>	'PHPExcel_Calculation_Logical::FALSE',
703
												 'argumentCount'	=>	'0'
704
												),
705
				'FDIST'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
706
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
707
												 'argumentCount'	=>	'3'
708
												),
709
				'FIND'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
710
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::SEARCHSENSITIVE',
711
												 'argumentCount'	=>	'2,3'
712
												),
713
				'FINDB'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
714
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::SEARCHSENSITIVE',
715
												 'argumentCount'	=>	'2,3'
716
												),
717
				'FINV'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
718
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
719
												 'argumentCount'	=>	'3'
720
												),
721
				'FISHER'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
722
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::FISHER',
723
												 'argumentCount'	=>	'1'
724
												),
725
				'FISHERINV'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
726
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::FISHERINV',
727
												 'argumentCount'	=>	'1'
728
												),
729
				'FIXED'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
730
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::FIXEDFORMAT',
731
												 'argumentCount'	=>	'1-3'
732
												),
733
				'FLOOR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
734
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::FLOOR',
735
												 'argumentCount'	=>	'2'
736
												),
737
				'FORECAST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
738
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::FORECAST',
739
												 'argumentCount'	=>	'3'
740
												),
741
				'FREQUENCY'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
742
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
743
												 'argumentCount'	=>	'2'
744
												),
745
				'FTEST'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
746
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
747
												 'argumentCount'	=>	'2'
748
												),
749
				'FV'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
750
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::FV',
751
												 'argumentCount'	=>	'3-5'
752
												),
753
				'FVSCHEDULE'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
754
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::FVSCHEDULE',
755
												 'argumentCount'	=>	'2'
756
												),
757
				'GAMMADIST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
758
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::GAMMADIST',
759
												 'argumentCount'	=>	'4'
760
												),
761
				'GAMMAINV'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
762
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::GAMMAINV',
763
												 'argumentCount'	=>	'3'
764
												),
765
				'GAMMALN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
766
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::GAMMALN',
767
												 'argumentCount'	=>	'1'
768
												),
769
				'GCD'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
770
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::GCD',
771
												 'argumentCount'	=>	'1+'
772
												),
773
				'GEOMEAN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
774
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::GEOMEAN',
775
												 'argumentCount'	=>	'1+'
776
												),
777
				'GESTEP'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
778
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::GESTEP',
779
												 'argumentCount'	=>	'1,2'
780
												),
781
				'GETPIVOTDATA'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
782
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
783
												 'argumentCount'	=>	'2+'
784
												),
785
				'GROWTH'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
786
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::GROWTH',
787
												 'argumentCount'	=>	'1-4'
788
												),
789
				'HARMEAN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
790
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::HARMEAN',
791
												 'argumentCount'	=>	'1+'
792
												),
793
				'HEX2BIN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
794
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::HEXTOBIN',
795
												 'argumentCount'	=>	'1,2'
796
												),
797
				'HEX2DEC'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
798
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::HEXTODEC',
799
												 'argumentCount'	=>	'1'
800
												),
801
				'HEX2OCT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
802
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::HEXTOOCT',
803
												 'argumentCount'	=>	'1,2'
804
												),
805
				'HLOOKUP'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
806
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
807
												 'argumentCount'	=>	'3,4'
808
												),
809
				'HOUR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
810
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::HOUROFDAY',
811
												 'argumentCount'	=>	'1'
812
												),
813
				'HYPERLINK'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
814
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::HYPERLINK',
815
												 'argumentCount'	=>	'1,2',
816
												 'passCellReference'=>	true
817
												),
818
				'HYPGEOMDIST'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
819
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::HYPGEOMDIST',
820
												 'argumentCount'	=>	'4'
821
												),
822
				'IF'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
823
												 'functionCall'		=>	'PHPExcel_Calculation_Logical::STATEMENT_IF',
824
												 'argumentCount'	=>	'1-3'
825
												),
826
				'IFERROR'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
827
												 'functionCall'		=>	'PHPExcel_Calculation_Logical::IFERROR',
828
												 'argumentCount'	=>	'2'
829
												),
830
				'IMABS'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
831
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMABS',
832
												 'argumentCount'	=>	'1'
833
												),
834
				'IMAGINARY'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
835
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMAGINARY',
836
												 'argumentCount'	=>	'1'
837
												),
838
				'IMARGUMENT'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
839
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMARGUMENT',
840
												 'argumentCount'	=>	'1'
841
												),
842
				'IMCONJUGATE'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
843
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMCONJUGATE',
844
												 'argumentCount'	=>	'1'
845
												),
846
				'IMCOS'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
847
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMCOS',
848
												 'argumentCount'	=>	'1'
849
												),
850
				'IMDIV'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
851
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMDIV',
852
												 'argumentCount'	=>	'2'
853
												),
854
				'IMEXP'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
855
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMEXP',
856
												 'argumentCount'	=>	'1'
857
												),
858
				'IMLN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
859
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMLN',
860
												 'argumentCount'	=>	'1'
861
												),
862
				'IMLOG10'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
863
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMLOG10',
864
												 'argumentCount'	=>	'1'
865
												),
866
				'IMLOG2'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
867
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMLOG2',
868
												 'argumentCount'	=>	'1'
869
												),
870
				'IMPOWER'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
871
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMPOWER',
872
												 'argumentCount'	=>	'2'
873
												),
874
				'IMPRODUCT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
875
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMPRODUCT',
876
												 'argumentCount'	=>	'1+'
877
												),
878
				'IMREAL'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
879
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMREAL',
880
												 'argumentCount'	=>	'1'
881
												),
882
				'IMSIN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
883
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMSIN',
884
												 'argumentCount'	=>	'1'
885
												),
886
				'IMSQRT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
887
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMSQRT',
888
												 'argumentCount'	=>	'1'
889
												),
890
				'IMSUB'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
891
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMSUB',
892
												 'argumentCount'	=>	'2'
893
												),
894
				'IMSUM'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
895
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::IMSUM',
896
												 'argumentCount'	=>	'1+'
897
												),
898
				'INDEX'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
899
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::INDEX',
900
												 'argumentCount'	=>	'1-4'
901
												),
902
				'INDIRECT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
903
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::INDIRECT',
904
												 'argumentCount'	=>	'1,2',
905
												 'passCellReference'=>	true
906
												),
907
				'INFO'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
908
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
909
												 'argumentCount'	=>	'1'
910
												),
911
				'INT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
912
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::INT',
913
												 'argumentCount'	=>	'1'
914
												),
915
				'INTERCEPT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
916
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::INTERCEPT',
917
												 'argumentCount'	=>	'2'
918
												),
919
				'INTRATE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
920
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::INTRATE',
921
												 'argumentCount'	=>	'4,5'
922
												),
923
				'IPMT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
924
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::IPMT',
925
												 'argumentCount'	=>	'4-6'
926
												),
927
				'IRR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
928
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::IRR',
929
												 'argumentCount'	=>	'1,2'
930
												),
931
				'ISBLANK'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
932
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::IS_BLANK',
933
												 'argumentCount'	=>	'1'
934
												),
935
				'ISERR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
936
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::IS_ERR',
937
												 'argumentCount'	=>	'1'
938
												),
939
				'ISERROR'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
940
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::IS_ERROR',
941
												 'argumentCount'	=>	'1'
942
												),
943
				'ISEVEN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
944
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::IS_EVEN',
945
												 'argumentCount'	=>	'1'
946
												),
947
				'ISLOGICAL'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
948
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::IS_LOGICAL',
949
												 'argumentCount'	=>	'1'
950
												),
951
				'ISNA'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
952
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::IS_NA',
953
												 'argumentCount'	=>	'1'
954
												),
955
				'ISNONTEXT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
956
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::IS_NONTEXT',
957
												 'argumentCount'	=>	'1'
958
												),
959
				'ISNUMBER'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
960
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::IS_NUMBER',
961
												 'argumentCount'	=>	'1'
962
												),
963
				'ISODD'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
964
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::IS_ODD',
965
												 'argumentCount'	=>	'1'
966
												),
967
				'ISPMT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
968
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::ISPMT',
969
												 'argumentCount'	=>	'4'
970
												),
971
				'ISREF'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
972
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
973
												 'argumentCount'	=>	'1'
974
												),
975
				'ISTEXT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
976
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::IS_TEXT',
977
												 'argumentCount'	=>	'1'
978
												),
979
				'JIS'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
980
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
981
												 'argumentCount'	=>	'1'
982
												),
983
				'KURT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
984
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::KURT',
985
												 'argumentCount'	=>	'1+'
986
												),
987
				'LARGE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
988
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::LARGE',
989
												 'argumentCount'	=>	'2'
990
												),
991
				'LCM'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
992
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::LCM',
993
												 'argumentCount'	=>	'1+'
994
												),
995
				'LEFT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
996
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::LEFT',
997
												 'argumentCount'	=>	'1,2'
998
												),
999
				'LEFTB'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1000
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::LEFT',
1001
												 'argumentCount'	=>	'1,2'
1002
												),
1003
				'LEN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1004
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::STRINGLENGTH',
1005
												 'argumentCount'	=>	'1'
1006
												),
1007
				'LENB'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1008
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::STRINGLENGTH',
1009
												 'argumentCount'	=>	'1'
1010
												),
1011
				'LINEST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1012
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::LINEST',
1013
												 'argumentCount'	=>	'1-4'
1014
												),
1015
				'LN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1016
												 'functionCall'		=>	'log',
1017
												 'argumentCount'	=>	'1'
1018
												),
1019
				'LOG'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1020
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::LOG_BASE',
1021
												 'argumentCount'	=>	'1,2'
1022
												),
1023
				'LOG10'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1024
												 'functionCall'		=>	'log10',
1025
												 'argumentCount'	=>	'1'
1026
												),
1027
				'LOGEST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1028
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::LOGEST',
1029
												 'argumentCount'	=>	'1-4'
1030
												),
1031
				'LOGINV'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1032
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::LOGINV',
1033
												 'argumentCount'	=>	'3'
1034
												),
1035
				'LOGNORMDIST'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1036
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::LOGNORMDIST',
1037
												 'argumentCount'	=>	'3'
1038
												),
1039
				'LOOKUP'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1040
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::LOOKUP',
1041
												 'argumentCount'	=>	'2,3'
1042
												),
1043
				'LOWER'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1044
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::LOWERCASE',
1045
												 'argumentCount'	=>	'1'
1046
												),
1047
				'MATCH'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1048
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::MATCH',
1049
												 'argumentCount'	=>	'2,3'
1050
												),
1051
				'MAX'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1052
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::MAX',
1053
												 'argumentCount'	=>	'1+'
1054
												),
1055
				'MAXA'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1056
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::MAXA',
1057
												 'argumentCount'	=>	'1+'
1058
												),
1059
				'MAXIF'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1060
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::MAXIF',
1061
												 'argumentCount'	=>	'2+'
1062
												),
1063
				'MDETERM'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1064
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::MDETERM',
1065
												 'argumentCount'	=>	'1'
1066
												),
1067
				'MDURATION'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1068
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1069
												 'argumentCount'	=>	'5,6'
1070
												),
1071
				'MEDIAN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1072
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::MEDIAN',
1073
												 'argumentCount'	=>	'1+'
1074
												),
1075
				'MEDIANIF'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1076
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1077
												 'argumentCount'	=>	'2+'
1078
												),
1079
				'MID'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1080
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::MID',
1081
												 'argumentCount'	=>	'3'
1082
												),
1083
				'MIDB'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1084
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::MID',
1085
												 'argumentCount'	=>	'3'
1086
												),
1087
				'MIN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1088
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::MIN',
1089
												 'argumentCount'	=>	'1+'
1090
												),
1091
				'MINA'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1092
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::MINA',
1093
												 'argumentCount'	=>	'1+'
1094
												),
1095
				'MINIF'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1096
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::MINIF',
1097
												 'argumentCount'	=>	'2+'
1098
												),
1099
				'MINUTE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1100
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::MINUTEOFHOUR',
1101
												 'argumentCount'	=>	'1'
1102
												),
1103
				'MINVERSE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1104
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::MINVERSE',
1105
												 'argumentCount'	=>	'1'
1106
												),
1107
				'MIRR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1108
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::MIRR',
1109
												 'argumentCount'	=>	'3'
1110
												),
1111
				'MMULT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1112
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::MMULT',
1113
												 'argumentCount'	=>	'2'
1114
												),
1115
				'MOD'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1116
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::MOD',
1117
												 'argumentCount'	=>	'2'
1118
												),
1119
				'MODE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1120
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::MODE',
1121
												 'argumentCount'	=>	'1+'
1122
												),
1123
				'MONTH'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1124
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::MONTHOFYEAR',
1125
												 'argumentCount'	=>	'1'
1126
												),
1127
				'MROUND'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1128
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::MROUND',
1129
												 'argumentCount'	=>	'2'
1130
												),
1131
				'MULTINOMIAL'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1132
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::MULTINOMIAL',
1133
												 'argumentCount'	=>	'1+'
1134
												),
1135
				'N'						=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1136
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::N',
1137
												 'argumentCount'	=>	'1'
1138
												),
1139
				'NA'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1140
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::NA',
1141
												 'argumentCount'	=>	'0'
1142
												),
1143
				'NEGBINOMDIST'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1144
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::NEGBINOMDIST',
1145
												 'argumentCount'	=>	'3'
1146
												),
1147
				'NETWORKDAYS'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1148
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::NETWORKDAYS',
1149
												 'argumentCount'	=>	'2+'
1150
												),
1151
				'NOMINAL'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1152
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::NOMINAL',
1153
												 'argumentCount'	=>	'2'
1154
												),
1155
				'NORMDIST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1156
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::NORMDIST',
1157
												 'argumentCount'	=>	'4'
1158
												),
1159
				'NORMINV'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1160
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::NORMINV',
1161
												 'argumentCount'	=>	'3'
1162
												),
1163
				'NORMSDIST'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1164
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::NORMSDIST',
1165
												 'argumentCount'	=>	'1'
1166
												),
1167
				'NORMSINV'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1168
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::NORMSINV',
1169
												 'argumentCount'	=>	'1'
1170
												),
1171
				'NOT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
1172
												 'functionCall'		=>	'PHPExcel_Calculation_Logical::NOT',
1173
												 'argumentCount'	=>	'1'
1174
												),
1175
				'NOW'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1176
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::DATETIMENOW',
1177
												 'argumentCount'	=>	'0'
1178
												),
1179
				'NPER'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1180
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::NPER',
1181
												 'argumentCount'	=>	'3-5'
1182
												),
1183
				'NPV'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1184
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::NPV',
1185
												 'argumentCount'	=>	'2+'
1186
												),
1187
				'OCT2BIN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
1188
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::OCTTOBIN',
1189
												 'argumentCount'	=>	'1,2'
1190
												),
1191
				'OCT2DEC'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
1192
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::OCTTODEC',
1193
												 'argumentCount'	=>	'1'
1194
												),
1195
				'OCT2HEX'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
1196
												 'functionCall'		=>	'PHPExcel_Calculation_Engineering::OCTTOHEX',
1197
												 'argumentCount'	=>	'1,2'
1198
												),
1199
				'ODD'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1200
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::ODD',
1201
												 'argumentCount'	=>	'1'
1202
												),
1203
				'ODDFPRICE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1204
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1205
												 'argumentCount'	=>	'8,9'
1206
												),
1207
				'ODDFYIELD'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1208
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1209
												 'argumentCount'	=>	'8,9'
1210
												),
1211
				'ODDLPRICE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1212
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1213
												 'argumentCount'	=>	'7,8'
1214
												),
1215
				'ODDLYIELD'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1216
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1217
												 'argumentCount'	=>	'7,8'
1218
												),
1219
				'OFFSET'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1220
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::OFFSET',
1221
												 'argumentCount'	=>	'3,5',
1222
												 'passCellReference'=>	true,
1223
												 'passByReference'	=>	array(true)
1224
												),
1225
				'OR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
1226
												 'functionCall'		=>	'PHPExcel_Calculation_Logical::LOGICAL_OR',
1227
												 'argumentCount'	=>	'1+'
1228
												),
1229
				'PEARSON'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1230
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::CORREL',
1231
												 'argumentCount'	=>	'2'
1232
												),
1233
				'PERCENTILE'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1234
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::PERCENTILE',
1235
												 'argumentCount'	=>	'2'
1236
												),
1237
				'PERCENTRANK'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1238
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::PERCENTRANK',
1239
												 'argumentCount'	=>	'2,3'
1240
												),
1241
				'PERMUT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1242
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::PERMUT',
1243
												 'argumentCount'	=>	'2'
1244
												),
1245
				'PHONETIC'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1246
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1247
												 'argumentCount'	=>	'1'
1248
												),
1249
				'PI'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1250
												 'functionCall'		=>	'pi',
1251
												 'argumentCount'	=>	'0'
1252
												),
1253
				'PMT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1254
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::PMT',
1255
												 'argumentCount'	=>	'3-5'
1256
												),
1257
				'POISSON'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1258
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::POISSON',
1259
												 'argumentCount'	=>	'3'
1260
												),
1261
				'POWER'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1262
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::POWER',
1263
												 'argumentCount'	=>	'2'
1264
												),
1265
				'PPMT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1266
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::PPMT',
1267
												 'argumentCount'	=>	'4-6'
1268
												),
1269
				'PRICE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1270
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::PRICE',
1271
												 'argumentCount'	=>	'6,7'
1272
												),
1273
				'PRICEDISC'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1274
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::PRICEDISC',
1275
												 'argumentCount'	=>	'4,5'
1276
												),
1277
				'PRICEMAT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1278
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::PRICEMAT',
1279
												 'argumentCount'	=>	'5,6'
1280
												),
1281
				'PROB'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1282
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1283
												 'argumentCount'	=>	'3,4'
1284
												),
1285
				'PRODUCT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1286
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::PRODUCT',
1287
												 'argumentCount'	=>	'1+'
1288
												),
1289
				'PROPER'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1290
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::PROPERCASE',
1291
												 'argumentCount'	=>	'1'
1292
												),
1293
				'PV'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1294
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::PV',
1295
												 'argumentCount'	=>	'3-5'
1296
												),
1297
				'QUARTILE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1298
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::QUARTILE',
1299
												 'argumentCount'	=>	'2'
1300
												),
1301
				'QUOTIENT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1302
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::QUOTIENT',
1303
												 'argumentCount'	=>	'2'
1304
												),
1305
				'RADIANS'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1306
												 'functionCall'		=>	'deg2rad',
1307
												 'argumentCount'	=>	'1'
1308
												),
1309
				'RAND'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1310
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::RAND',
1311
												 'argumentCount'	=>	'0'
1312
												),
1313
				'RANDBETWEEN'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1314
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::RAND',
1315
												 'argumentCount'	=>	'2'
1316
												),
1317
				'RANK'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1318
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::RANK',
1319
												 'argumentCount'	=>	'2,3'
1320
												),
1321
				'RATE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1322
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::RATE',
1323
												 'argumentCount'	=>	'3-6'
1324
												),
1325
				'RECEIVED'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1326
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::RECEIVED',
1327
												 'argumentCount'	=>	'4-5'
1328
												),
1329
				'REPLACE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1330
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::REPLACE',
1331
												 'argumentCount'	=>	'4'
1332
												),
1333
				'REPLACEB'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1334
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::REPLACE',
1335
												 'argumentCount'	=>	'4'
1336
												),
1337
				'REPT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1338
												 'functionCall'		=>	'str_repeat',
1339
												 'argumentCount'	=>	'2'
1340
												),
1341
				'RIGHT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1342
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::RIGHT',
1343
												 'argumentCount'	=>	'1,2'
1344
												),
1345
				'RIGHTB'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1346
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::RIGHT',
1347
												 'argumentCount'	=>	'1,2'
1348
												),
1349
				'ROMAN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1350
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::ROMAN',
1351
												 'argumentCount'	=>	'1,2'
1352
												),
1353
				'ROUND'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1354
												 'functionCall'		=>	'round',
1355
												 'argumentCount'	=>	'2'
1356
												),
1357
				'ROUNDDOWN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1358
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::ROUNDDOWN',
1359
												 'argumentCount'	=>	'2'
1360
												),
1361
				'ROUNDUP'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1362
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::ROUNDUP',
1363
												 'argumentCount'	=>	'2'
1364
												),
1365
				'ROW'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1366
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::ROW',
1367
												 'argumentCount'	=>	'-1',
1368
												 'passByReference'	=>	array(true)
1369
												),
1370
				'ROWS'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1371
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::ROWS',
1372
												 'argumentCount'	=>	'1'
1373
												),
1374
				'RSQ'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1375
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::RSQ',
1376
												 'argumentCount'	=>	'2'
1377
												),
1378
				'RTD'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1379
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1380
												 'argumentCount'	=>	'1+'
1381
												),
1382
				'SEARCH'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1383
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::SEARCHINSENSITIVE',
1384
												 'argumentCount'	=>	'2,3'
1385
												),
1386
				'SEARCHB'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1387
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::SEARCHINSENSITIVE',
1388
												 'argumentCount'	=>	'2,3'
1389
												),
1390
				'SECOND'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1391
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::SECONDOFMINUTE',
1392
												 'argumentCount'	=>	'1'
1393
												),
1394
				'SERIESSUM'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1395
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SERIESSUM',
1396
												 'argumentCount'	=>	'4'
1397
												),
1398
				'SIGN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1399
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SIGN',
1400
												 'argumentCount'	=>	'1'
1401
												),
1402
				'SIN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1403
												 'functionCall'		=>	'sin',
1404
												 'argumentCount'	=>	'1'
1405
												),
1406
				'SINH'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1407
												 'functionCall'		=>	'sinh',
1408
												 'argumentCount'	=>	'1'
1409
												),
1410
				'SKEW'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1411
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::SKEW',
1412
												 'argumentCount'	=>	'1+'
1413
												),
1414
				'SLN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1415
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::SLN',
1416
												 'argumentCount'	=>	'3'
1417
												),
1418
				'SLOPE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1419
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::SLOPE',
1420
												 'argumentCount'	=>	'2'
1421
												),
1422
				'SMALL'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1423
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::SMALL',
1424
												 'argumentCount'	=>	'2'
1425
												),
1426
				'SQRT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1427
												 'functionCall'		=>	'sqrt',
1428
												 'argumentCount'	=>	'1'
1429
												),
1430
				'SQRTPI'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1431
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SQRTPI',
1432
												 'argumentCount'	=>	'1'
1433
												),
1434
				'STANDARDIZE'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1435
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::STANDARDIZE',
1436
												 'argumentCount'	=>	'3'
1437
												),
1438
				'STDEV'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1439
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::STDEV',
1440
												 'argumentCount'	=>	'1+'
1441
												),
1442
				'STDEVA'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1443
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::STDEVA',
1444
												 'argumentCount'	=>	'1+'
1445
												),
1446
				'STDEVP'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1447
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::STDEVP',
1448
												 'argumentCount'	=>	'1+'
1449
												),
1450
				'STDEVPA'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1451
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::STDEVPA',
1452
												 'argumentCount'	=>	'1+'
1453
												),
1454
				'STEYX'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1455
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::STEYX',
1456
												 'argumentCount'	=>	'2'
1457
												),
1458
				'SUBSTITUTE'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1459
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::SUBSTITUTE',
1460
												 'argumentCount'	=>	'3,4'
1461
												),
1462
				'SUBTOTAL'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1463
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SUBTOTAL',
1464
												 'argumentCount'	=>	'2+'
1465
												),
1466
				'SUM'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1467
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SUM',
1468
												 'argumentCount'	=>	'1+'
1469
												),
1470
				'SUMIF'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1471
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SUMIF',
1472
												 'argumentCount'	=>	'2,3'
1473
												),
1474
				'SUMIFS'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1475
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1476
												 'argumentCount'	=>	'?'
1477
												),
1478
				'SUMPRODUCT'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1479
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SUMPRODUCT',
1480
												 'argumentCount'	=>	'1+'
1481
												),
1482
				'SUMSQ'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1483
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SUMSQ',
1484
												 'argumentCount'	=>	'1+'
1485
												),
1486
				'SUMX2MY2'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1487
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SUMX2MY2',
1488
												 'argumentCount'	=>	'2'
1489
												),
1490
				'SUMX2PY2'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1491
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SUMX2PY2',
1492
												 'argumentCount'	=>	'2'
1493
												),
1494
				'SUMXMY2'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1495
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::SUMXMY2',
1496
												 'argumentCount'	=>	'2'
1497
												),
1498
				'SYD'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1499
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::SYD',
1500
												 'argumentCount'	=>	'4'
1501
												),
1502
				'T'						=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1503
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::RETURNSTRING',
1504
												 'argumentCount'	=>	'1'
1505
												),
1506
				'TAN'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1507
												 'functionCall'		=>	'tan',
1508
												 'argumentCount'	=>	'1'
1509
												),
1510
				'TANH'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1511
												 'functionCall'		=>	'tanh',
1512
												 'argumentCount'	=>	'1'
1513
												),
1514
				'TBILLEQ'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1515
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::TBILLEQ',
1516
												 'argumentCount'	=>	'3'
1517
												),
1518
				'TBILLPRICE'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1519
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::TBILLPRICE',
1520
												 'argumentCount'	=>	'3'
1521
												),
1522
				'TBILLYIELD'			=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1523
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::TBILLYIELD',
1524
												 'argumentCount'	=>	'3'
1525
												),
1526
				'TDIST'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1527
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::TDIST',
1528
												 'argumentCount'	=>	'3'
1529
												),
1530
				'TEXT'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1531
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::TEXTFORMAT',
1532
												 'argumentCount'	=>	'2'
1533
												),
1534
				'TIME'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1535
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::TIME',
1536
												 'argumentCount'	=>	'3'
1537
												),
1538
				'TIMEVALUE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1539
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::TIMEVALUE',
1540
												 'argumentCount'	=>	'1'
1541
												),
1542
				'TINV'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1543
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::TINV',
1544
												 'argumentCount'	=>	'2'
1545
												),
1546
				'TODAY'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1547
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::DATENOW',
1548
												 'argumentCount'	=>	'0'
1549
												),
1550
				'TRANSPOSE'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1551
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::TRANSPOSE',
1552
												 'argumentCount'	=>	'1'
1553
												),
1554
				'TREND'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1555
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::TREND',
1556
												 'argumentCount'	=>	'1-4'
1557
												),
1558
				'TRIM'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1559
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::TRIMSPACES',
1560
												 'argumentCount'	=>	'1'
1561
												),
1562
				'TRIMMEAN'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1563
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::TRIMMEAN',
1564
												 'argumentCount'	=>	'2'
1565
												),
1566
				'TRUE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
1567
												 'functionCall'		=>	'PHPExcel_Calculation_Logical::TRUE',
1568
												 'argumentCount'	=>	'0'
1569
												),
1570
				'TRUNC'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1571
												 'functionCall'		=>	'PHPExcel_Calculation_MathTrig::TRUNC',
1572
												 'argumentCount'	=>	'1,2'
1573
												),
1574
				'TTEST'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1575
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1576
												 'argumentCount'	=>	'4'
1577
												),
1578
				'TYPE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1579
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::TYPE',
1580
												 'argumentCount'	=>	'1'
1581
												),
1582
				'UPPER'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1583
												 'functionCall'		=>	'PHPExcel_Calculation_TextData::UPPERCASE',
1584
												 'argumentCount'	=>	'1'
1585
												),
1586
				'USDOLLAR'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1587
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1588
												 'argumentCount'	=>	'2'
1589
												),
1590
				'VALUE'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1591
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1592
												 'argumentCount'	=>	'1'
1593
												),
1594
				'VAR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1595
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::VARFunc',
1596
												 'argumentCount'	=>	'1+'
1597
												),
1598
				'VARA'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1599
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::VARA',
1600
												 'argumentCount'	=>	'1+'
1601
												),
1602
				'VARP'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1603
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::VARP',
1604
												 'argumentCount'	=>	'1+'
1605
												),
1606
				'VARPA'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1607
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::VARPA',
1608
												 'argumentCount'	=>	'1+'
1609
												),
1610
				'VDB'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1611
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1612
												 'argumentCount'	=>	'5-7'
1613
												),
1614
				'VERSION'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1615
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::VERSION',
1616
												 'argumentCount'	=>	'0'
1617
												),
1618
				'VLOOKUP'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1619
												 'functionCall'		=>	'PHPExcel_Calculation_LookupRef::VLOOKUP',
1620
												 'argumentCount'	=>	'3,4'
1621
												),
1622
				'WEEKDAY'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1623
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::DAYOFWEEK',
1624
												 'argumentCount'	=>	'1,2'
1625
												),
1626
				'WEEKNUM'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1627
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::WEEKOFYEAR',
1628
												 'argumentCount'	=>	'1,2'
1629
												),
1630
				'WEIBULL'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1631
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::WEIBULL',
1632
												 'argumentCount'	=>	'4'
1633
												),
1634
				'WORKDAY'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1635
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::WORKDAY',
1636
												 'argumentCount'	=>	'2+'
1637
												),
1638
				'XIRR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1639
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::XIRR',
1640
												 'argumentCount'	=>	'2,3'
1641
												),
1642
				'XNPV'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1643
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::XNPV',
1644
												 'argumentCount'	=>	'3'
1645
												),
1646
				'YEAR'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1647
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::YEAR',
1648
												 'argumentCount'	=>	'1'
1649
												),
1650
				'YEARFRAC'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1651
												 'functionCall'		=>	'PHPExcel_Calculation_DateTime::YEARFRAC',
1652
												 'argumentCount'	=>	'2,3'
1653
												),
1654
				'YIELD'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1655
												 'functionCall'		=>	'PHPExcel_Calculation_Functions::DUMMY',
1656
												 'argumentCount'	=>	'6,7'
1657
												),
1658
				'YIELDDISC'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1659
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::YIELDDISC',
1660
												 'argumentCount'	=>	'4,5'
1661
												),
1662
				'YIELDMAT'				=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1663
												 'functionCall'		=>	'PHPExcel_Calculation_Financial::YIELDMAT',
1664
												 'argumentCount'	=>	'5,6'
1665
												),
1666
				'ZTEST'					=> array('category'			=>	PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1667
												 'functionCall'		=>	'PHPExcel_Calculation_Statistical::ZTEST',
1668
												 'argumentCount'	=>	'2-3'
1669
												)
1670
			);
1671
1672
1673
	//	Internal functions used for special control purposes
1674
	private static $_controlFunctions = array(
1675
				'MKMATRIX'	=> array('argumentCount'	=>	'*',
1676
									 'functionCall'		=>	'self::_mkMatrix'
1677
									)
1678
			);
1679
1680
1681
1682
1683
	private function __construct() {
1684
		$localeFileDirectory = PHPEXCEL_ROOT.'PHPExcel/locale/';
1685
		foreach (glob($localeFileDirectory.'/*',GLOB_ONLYDIR) as $filename) {
1686
			$filename = substr($filename,strlen($localeFileDirectory)+1);
1687
			if ($filename != 'en') {
1688
				self::$_validLocaleLanguages[] = $filename;
1689
			}
1690
		}
1691
1692
		$setPrecision = (PHP_INT_SIZE == 4) ? 12 : 16;
1693
		$this->_savedPrecision = ini_get('precision');
0 ignored issues
show
Documentation Bug introduced by
The property $_savedPrecision was declared of type integer, but ini_get('precision') 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...
1694
		if ($this->_savedPrecision < $setPrecision) {
1695
			ini_set('precision',$setPrecision);
1696
		}
1697
	}	//	function __construct()
1698
1699
1700
	public function __destruct() {
1701
		if ($this->_savedPrecision != ini_get('precision')) {
1702
			ini_set('precision',$this->_savedPrecision);
1703
		}
1704
	}
1705
1706
	/**
1707
	 * Get an instance of this class
1708
	 *
1709
	 * @access	public
1710
	 * @return PHPExcel_Calculation
1711
	 */
1712
	public static function getInstance() {
1713
		if (!isset(self::$_instance) || (self::$_instance === NULL)) {
1714
			self::$_instance = new PHPExcel_Calculation();
1715
		}
1716
1717
		return self::$_instance;
1718
	}	//	function getInstance()
1719
1720
1721
	/**
1722
	 * Flush the calculation cache for any existing instance of this class
1723
	 *		but only if a PHPExcel_Calculation instance exists
1724
	 *
1725
	 * @access	public
1726
	 * @return null
1727
	 */
1728
	public static function flushInstance() {
1729
		if (isset(self::$_instance) && (self::$_instance !== NULL)) {
1730
			self::$_instance->clearCalculationCache();
1731
		}
1732
	}	//	function flushInstance()
1733
1734
1735
	/**
1736
	 * __clone implementation. Cloning should not be allowed in a Singleton!
1737
	 *
1738
	 * @access	public
1739
	 * @throws	Exception
1740
	 */
1741
	public final function __clone() {
0 ignored issues
show
Coding Style introduced by
As per PSR2, final should precede the visibility keyword.
Loading history...
1742
		throw new Exception ('Cloning a Singleton is not allowed!');
1743
	}	//	function __clone()
1744
1745
1746
	/**
1747
	 * Return the locale-specific translation of TRUE
1748
	 *
1749
	 * @access	public
1750
	 * @return	 string		locale-specific translation of TRUE
1751
	 */
1752
	public static function getTRUE() {
1753
		return self::$_localeBoolean['TRUE'];
1754
	}
1755
1756
	/**
1757
	 * Return the locale-specific translation of FALSE
1758
	 *
1759
	 * @access	public
1760
	 * @return	 string		locale-specific translation of FALSE
1761
	 */
1762
	public static function getFALSE() {
1763
		return self::$_localeBoolean['FALSE'];
1764
	}
1765
1766
	/**
1767
	 * Set the Array Return Type (Array or Value of first element in the array)
1768
	 *
1769
	 * @access	public
1770
	 * @param	 string	$returnType			Array return type
1771
	 * @return	 boolean					Success or failure
1772
	 */
1773
	public static function setArrayReturnType($returnType) {
1774
		if (($returnType == self::RETURN_ARRAY_AS_VALUE) ||
1775
			($returnType == self::RETURN_ARRAY_AS_ERROR) ||
1776
			($returnType == self::RETURN_ARRAY_AS_ARRAY)) {
1777
			self::$returnArrayAsType = $returnType;
1778
			return true;
1779
		}
1780
		return false;
1781
	}	//	function setExcelCalendar()
1782
1783
1784
	/**
1785
	 * Return the Array Return Type (Array or Value of first element in the array)
1786
	 *
1787
	 * @access	public
1788
	 * @return	 string		$returnType			Array return type
1789
	 */
1790
	public static function getArrayReturnType() {
1791
		return self::$returnArrayAsType;
1792
	}	//	function getExcelCalendar()
1793
1794
1795
	/**
1796
	 * Is calculation caching enabled?
1797
	 *
1798
	 * @access	public
1799
	 * @return boolean
1800
	 */
1801
	public function getCalculationCacheEnabled() {
1802
		return self::$_calculationCacheEnabled;
1803
	}	//	function getCalculationCacheEnabled()
1804
1805
1806
	/**
1807
	 * Enable/disable calculation cache
1808
	 *
1809
	 * @access	public
1810
	 * @param boolean $pValue
1811
	 */
1812
	public function setCalculationCacheEnabled($pValue = true) {
1813
		self::$_calculationCacheEnabled = $pValue;
1814
		$this->clearCalculationCache();
1815
	}	//	function setCalculationCacheEnabled()
1816
1817
1818
	/**
1819
	 * Enable calculation cache
1820
	 */
1821
	public function enableCalculationCache() {
1822
		$this->setCalculationCacheEnabled(true);
1823
	}	//	function enableCalculationCache()
1824
1825
1826
	/**
1827
	 * Disable calculation cache
1828
	 */
1829
	public function disableCalculationCache() {
1830
		$this->setCalculationCacheEnabled(false);
1831
	}	//	function disableCalculationCache()
1832
1833
1834
	/**
1835
	 * Clear calculation cache
1836
	 */
1837
	public function clearCalculationCache() {
1838
		self::$_calculationCache = array();
1839
	}	//	function clearCalculationCache()
1840
1841
1842
	/**
1843
	 * Get calculation cache expiration time
1844
	 *
1845
	 * @return float
1846
	 */
1847
	public function getCalculationCacheExpirationTime() {
1848
		return self::$_calculationCacheExpirationTime;
1849
	}	//	getCalculationCacheExpirationTime()
1850
1851
1852
	/**
1853
	 * Set calculation cache expiration time
1854
	 *
1855
	 * @param float $pValue
1856
	 */
1857
	public function setCalculationCacheExpirationTime($pValue = 15) {
1858
		self::$_calculationCacheExpirationTime = $pValue;
0 ignored issues
show
Documentation Bug introduced by
The property $_calculationCacheExpirationTime was declared of type double, but $pValue is of type integer. 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...
1859
	}	//	function setCalculationCacheExpirationTime()
1860
1861
1862
1863
1864
	/**
1865
	 * Get the currently defined locale code
1866
	 *
1867
	 * @return string
1868
	 */
1869
	public function getLocale() {
1870
		return self::$_localeLanguage;
1871
	}	//	function getLocale()
1872
1873
1874
	/**
1875
	 * Set the locale code
1876
	 *
1877
	 * @return boolean
1878
	 */
1879
	public function setLocale($locale='en_us') {
1880
		//	Identify our locale and language
1881
		$language = $locale = strtolower($locale);
1882
		if (strpos($locale,'_') !== false) {
1883
			list($language) = explode('_',$locale);
1884
		}
1885
1886
		//	Test whether we have any language data for this language (any locale)
1887
		if (in_array($language,self::$_validLocaleLanguages)) {
1888
			//	initialise language/locale settings
1889
			self::$_localeFunctions = array();
1890
			self::$_localeArgumentSeparator = ',';
1891
			self::$_localeBoolean = array('TRUE' => 'TRUE', 'FALSE' => 'FALSE', 'NULL' => 'NULL');
1892
			//	Default is English, if user isn't requesting english, then read the necessary data from the locale files
1893
			if ($locale != 'en_us') {
1894
				//	Search for a file with a list of function names for locale
1895
				$functionNamesFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.str_replace('_',DIRECTORY_SEPARATOR,$locale).DIRECTORY_SEPARATOR.'functions';
1896
				if (!file_exists($functionNamesFile)) {
1897
					//	If there isn't a locale specific function file, look for a language specific function file
1898
					$functionNamesFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.'functions';
1899
					if (!file_exists($functionNamesFile)) {
1900
						return false;
1901
					}
1902
				}
1903
				//	Retrieve the list of locale or language specific function names
1904
				$localeFunctions = file($functionNamesFile,FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
1905
				foreach ($localeFunctions as $localeFunction) {
1906
					list($localeFunction) = explode('##',$localeFunction);	//	Strip out comments
1907
					if (strpos($localeFunction,'=') !== false) {
1908
						list($fName,$lfName) = explode('=',$localeFunction);
1909
						$fName = trim($fName);
1910
						$lfName = trim($lfName);
1911
						if ((isset(self::$_PHPExcelFunctions[$fName])) && ($lfName != '') && ($fName != $lfName)) {
1912
							self::$_localeFunctions[$fName] = $lfName;
1913
						}
1914
					}
1915
				}
1916
				//	Default the TRUE and FALSE constants to the locale names of the TRUE() and FALSE() functions
1917
				if (isset(self::$_localeFunctions['TRUE'])) { self::$_localeBoolean['TRUE'] = self::$_localeFunctions['TRUE']; }
1918
				if (isset(self::$_localeFunctions['FALSE'])) { self::$_localeBoolean['FALSE'] = self::$_localeFunctions['FALSE']; }
1919
1920
				$configFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.str_replace('_',DIRECTORY_SEPARATOR,$locale).DIRECTORY_SEPARATOR.'config';
1921
				if (!file_exists($configFile)) {
1922
					$configFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.'config';
1923
				}
1924
				if (file_exists($configFile)) {
1925
					$localeSettings = file($configFile,FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
1926
					foreach ($localeSettings as $localeSetting) {
1927
						list($localeSetting) = explode('##',$localeSetting);	//	Strip out comments
1928
						if (strpos($localeSetting,'=') !== false) {
1929
							list($settingName,$settingValue) = explode('=',$localeSetting);
1930
							$settingName = strtoupper(trim($settingName));
1931
							switch ($settingName) {
1932
								case 'ARGUMENTSEPARATOR' :
1933
									self::$_localeArgumentSeparator = trim($settingValue);
1934
									break;
1935
							}
1936
						}
1937
					}
1938
				}
1939
			}
1940
1941
			self::$functionReplaceFromExcel = self::$functionReplaceToExcel =
1942
			self::$functionReplaceFromLocale = self::$functionReplaceToLocale = null;
1943
			self::$_localeLanguage = $locale;
1944
			return true;
1945
		}
1946
		return false;
1947
	}	//	function setLocale()
1948
1949
1950
1951
	public static function _translateSeparator($fromSeparator,$toSeparator,$formula,&$inBraces) {
1952
		$strlen = mb_strlen($formula);
1953
		for ($i = 0; $i < $strlen; ++$i) {
1954
			$chr = mb_substr($formula,$i,1);
1955
			switch ($chr) {
1956
				case '{' :	$inBraces = true;
1957
							break;
1958
				case '}' :	$inBraces = false;
1959
							break;
1960
				case $fromSeparator :
1961
							if (!$inBraces) {
1962
								$formula = mb_substr($formula,0,$i).$toSeparator.mb_substr($formula,$i+1);
1963
							}
1964
			}
1965
		}
1966
		return $formula;
1967
	}
1968
1969
	private static function _translateFormula($from,$to,$formula,$fromSeparator,$toSeparator) {
1970
		//	Convert any Excel function names to the required language
1971
		if (self::$_localeLanguage !== 'en_us') {
1972
			$inBraces = false;
1973
			//	If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
1974
			if (strpos($formula,'"') !== false) {
1975
				//	So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
1976
				//		the formula
1977
				$temp = explode('"',$formula);
1978
				$i = false;
1979
				foreach($temp as &$value) {
1980
					//	Only count/replace in alternating array entries
1981 View Code Duplication
					if ($i = !$i) {
1982
						$value = preg_replace($from,$to,$value);
1983
						$value = self::_translateSeparator($fromSeparator,$toSeparator,$value,$inBraces);
1984
					}
1985
				}
1986
				unset($value);
1987
				//	Then rebuild the formula string
1988
				$formula = implode('"',$temp);
1989 View Code Duplication
			} else {
1990
				//	If there's no quoted strings, then we do a simple count/replace
1991
				$formula = preg_replace($from,$to,$formula);
1992
				$formula = self::_translateSeparator($fromSeparator,$toSeparator,$formula,$inBraces);
1993
			}
1994
		}
1995
1996
		return $formula;
1997
	}
1998
1999
	private static $functionReplaceFromExcel	= null;
2000
	private static $functionReplaceToLocale		= null;
2001
2002 View Code Duplication
	public function _translateFormulaToLocale($formula) {
2003
		if (self::$functionReplaceFromExcel === NULL) {
2004
			self::$functionReplaceFromExcel = array();
2005
			foreach(array_keys(self::$_localeFunctions) as $excelFunctionName) {
2006
				self::$functionReplaceFromExcel[] = '/(@?[^\w\.])'.preg_quote($excelFunctionName).'([\s]*\()/Ui';
2007
			}
2008
			foreach(array_keys(self::$_localeBoolean) as $excelBoolean) {
2009
				self::$functionReplaceFromExcel[] = '/(@?[^\w\.])'.preg_quote($excelBoolean).'([^\w\.])/Ui';
2010
			}
2011
2012
		}
2013
2014
		if (self::$functionReplaceToLocale === NULL) {
2015
			self::$functionReplaceToLocale = array();
2016
			foreach(array_values(self::$_localeFunctions) as $localeFunctionName) {
2017
				self::$functionReplaceToLocale[] = '$1'.trim($localeFunctionName).'$2';
2018
			}
2019
			foreach(array_values(self::$_localeBoolean) as $localeBoolean) {
2020
				self::$functionReplaceToLocale[] = '$1'.trim($localeBoolean).'$2';
2021
			}
2022
		}
2023
2024
		return self::_translateFormula(self::$functionReplaceFromExcel,self::$functionReplaceToLocale,$formula,',',self::$_localeArgumentSeparator);
2025
	}	//	function _translateFormulaToLocale()
2026
2027
2028
	private static $functionReplaceFromLocale	= null;
2029
	private static $functionReplaceToExcel		= null;
2030
2031 View Code Duplication
	public function _translateFormulaToEnglish($formula) {
2032
		if (self::$functionReplaceFromLocale === NULL) {
2033
			self::$functionReplaceFromLocale = array();
2034
			foreach(array_values(self::$_localeFunctions) as $localeFunctionName) {
2035
				self::$functionReplaceFromLocale[] = '/(@?[^\w\.])'.preg_quote($localeFunctionName).'([\s]*\()/Ui';
2036
			}
2037
			foreach(array_values(self::$_localeBoolean) as $excelBoolean) {
2038
				self::$functionReplaceFromLocale[] = '/(@?[^\w\.])'.preg_quote($excelBoolean).'([^\w\.])/Ui';
2039
			}
2040
		}
2041
2042
		if (self::$functionReplaceToExcel === NULL) {
2043
			self::$functionReplaceToExcel = array();
2044
			foreach(array_keys(self::$_localeFunctions) as $excelFunctionName) {
2045
				self::$functionReplaceToExcel[] = '$1'.trim($excelFunctionName).'$2';
2046
			}
2047
			foreach(array_keys(self::$_localeBoolean) as $excelBoolean) {
2048
				self::$functionReplaceToExcel[] = '$1'.trim($excelBoolean).'$2';
2049
			}
2050
		}
2051
2052
		return self::_translateFormula(self::$functionReplaceFromLocale,self::$functionReplaceToExcel,$formula,self::$_localeArgumentSeparator,',');
2053
	}	//	function _translateFormulaToEnglish()
2054
2055
2056
	public static function _localeFunc($function) {
2057
		if (self::$_localeLanguage !== 'en_us') {
2058
			$functionName = trim($function,'(');
2059
			if (isset(self::$_localeFunctions[$functionName])) {
2060
				$brace = ($functionName != $function);
2061
				$function = self::$_localeFunctions[$functionName];
2062
				if ($brace) { $function .= '('; }
2063
			}
2064
		}
2065
		return $function;
2066
	}
2067
2068
2069
2070
2071
	/**
2072
	 * Wrap string values in quotes
2073
	 *
2074
	 * @param mixed $value
2075
	 * @return mixed
2076
	 */
2077
	public static function _wrapResult($value) {
2078
		if (is_string($value)) {
2079
			//	Error values cannot be "wrapped"
2080
			if (preg_match('/^'.self::CALCULATION_REGEXP_ERROR.'$/i', $value, $match)) {
2081
				//	Return Excel errors "as is"
2082
				return $value;
2083
			}
2084
			//	Return strings wrapped in quotes
2085
			return '"'.$value.'"';
2086
		//	Convert numeric errors to NaN error
2087 View Code Duplication
		} else if((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
2088
			return PHPExcel_Calculation_Functions::NaN();
2089
		}
2090
2091
		return $value;
2092
	}	//	function _wrapResult()
2093
2094
2095
	/**
2096
	 * Remove quotes used as a wrapper to identify string values
2097
	 *
2098
	 * @param mixed $value
2099
	 * @return mixed
2100
	 */
2101
	public static function _unwrapResult($value) {
2102
		if (is_string($value)) {
2103
			if ((isset($value{0})) && ($value{0} == '"') && (substr($value,-1) == '"')) {
2104
				return substr($value,1,-1);
2105
			}
2106
		//	Convert numeric errors to NaN error
2107 View Code Duplication
		} else if((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
2108
			return PHPExcel_Calculation_Functions::NaN();
2109
		}
2110
		return $value;
2111
	}	//	function _unwrapResult()
2112
2113
2114
2115
2116
	/**
2117
	 * Calculate cell value (using formula from a cell ID)
2118
	 * Retained for backward compatibility
2119
	 *
2120
	 * @access	public
2121
	 * @param	PHPExcel_Cell	$pCell	Cell to calculate
2122
	 * @return	mixed
2123
	 * @throws	Exception
2124
	 */
2125
	public function calculate(PHPExcel_Cell $pCell = null) {
2126
		try {
2127
			return $this->calculateCellValue($pCell);
2128
		} catch (Exception $e) {
2129
			throw(new Exception($e->getMessage()));
2130
		}
2131
	}	//	function calculate()
2132
2133
2134
	/**
2135
	 * Calculate the value of a cell formula
2136
	 *
2137
	 * @access	public
2138
	 * @param	PHPExcel_Cell	$pCell		Cell to calculate
2139
	 * @param	Boolean			$resetLog	Flag indicating whether the debug log should be reset or not
2140
	 * @return	mixed
2141
	 * @throws	Exception
2142
	 */
2143
	public function calculateCellValue(PHPExcel_Cell $pCell = null, $resetLog = true) {
2144
		if ($resetLog) {
2145
			//	Initialise the logging settings if requested
2146
			$this->formulaError = null;
2147
			$this->debugLog = $this->debugLogStack = array();
2148
			$this->_cyclicFormulaCount = 1;
2149
2150
			$returnArrayAsType = self::$returnArrayAsType;
2151
			self::$returnArrayAsType = self::RETURN_ARRAY_AS_ARRAY;
2152
		}
2153
2154
		//	Read the formula from the cell
2155
		if ($pCell === NULL) {
2156
			return NULL;
2157
		}
2158
2159
		if ($resetLog) {
2160
			self::$returnArrayAsType = $returnArrayAsType;
0 ignored issues
show
Bug introduced by
The variable $returnArrayAsType 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...
2161
		}
2162
		//	Execute the calculation for the cell formula
2163
		try {
2164
			$result = self::_unwrapResult($this->_calculateFormulaValue($pCell->getValue(), $pCell->getCoordinate(), $pCell));
2165
		} catch (Exception $e) {
2166
			throw(new Exception($e->getMessage()));
2167
		}
2168
2169
		if ((is_array($result)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) {
2170
			$testResult = PHPExcel_Calculation_Functions::flattenArray($result);
2171
			if (self::$returnArrayAsType == self::RETURN_ARRAY_AS_ERROR) {
2172
				return PHPExcel_Calculation_Functions::VALUE();
2173
			}
2174
			//	If there's only a single cell in the array, then we allow it
2175
			if (count($testResult) != 1) {
2176
				//	If keys are numeric, then it's a matrix result rather than a cell range result, so we permit it
2177
				$r = array_keys($result);
2178
				$r = array_shift($r);
2179
				if (!is_numeric($r)) { return PHPExcel_Calculation_Functions::VALUE(); }
2180
				if (is_array($result[$r])) {
2181
					$c = array_keys($result[$r]);
2182
					$c = array_shift($c);
2183
					if (!is_numeric($c)) {
2184
						return PHPExcel_Calculation_Functions::VALUE();
2185
					}
2186
				}
2187
			}
2188
			$result = array_shift($testResult);
2189
		}
2190
2191 View Code Duplication
		if ($result === NULL) {
2192
			return 0;
2193
		} elseif((is_float($result)) && ((is_nan($result)) || (is_infinite($result)))) {
2194
			return PHPExcel_Calculation_Functions::NaN();
2195
		}
2196
		return $result;
2197
	}	//	function calculateCellValue(
2198
2199
2200
	/**
2201
	 * Validate and parse a formula string
2202
	 *
2203
	 * @param	string		$formula		Formula to parse
2204
	 * @return	array
2205
	 * @throws	Exception
2206
	 */
2207
	public function parseFormula($formula) {
2208
		//	Basic validation that this is indeed a formula
2209
		//	We return an empty array if not
2210
		$formula = trim($formula);
2211
		if ((!isset($formula{0})) || ($formula{0} != '=')) return array();
2212
		$formula = ltrim(substr($formula,1));
2213
		if (!isset($formula{0})) return array();
2214
2215
		//	Parse the formula and return the token stack
2216
		return $this->_parseFormula($formula);
2217
	}	//	function parseFormula()
2218
2219
2220
	/**
2221
	 * Calculate the value of a formula
2222
	 *
2223
	 * @param	string		$formula		Formula to parse
2224
	 * @return	mixed
2225
	 * @throws	Exception
2226
	 */
2227
	public function calculateFormula($formula, $cellID=null, PHPExcel_Cell $pCell = null) {
2228
		//	Initialise the logging settings
2229
		$this->formulaError = null;
2230
		$this->debugLog = $this->debugLogStack = array();
2231
2232
		//	Disable calculation cacheing because it only applies to cell calculations, not straight formulae
2233
		//	But don't actually flush any cache
2234
		$resetCache = $this->getCalculationCacheEnabled();
2235
		self::$_calculationCacheEnabled = false;
2236
		//	Execute the calculation
2237
		try {
2238
			$result = self::_unwrapResult($this->_calculateFormulaValue($formula, $cellID, $pCell));
2239
		} catch (Exception $e) {
2240
			throw(new Exception($e->getMessage()));
2241
		}
2242
2243
		//	Reset calculation cacheing to its previous state
2244
		self::$_calculationCacheEnabled = $resetCache;
2245
2246
		return $result;
2247
	}	//	function calculateFormula()
2248
2249
2250
	/**
2251
	 * Parse a cell formula and calculate its value
2252
	 *
2253
	 * @param	string			$formula	The formula to parse and calculate
2254
	 * @param	string			$cellID		The ID (e.g. A3) of the cell that we are calculating
2255
	 * @param	PHPExcel_Cell	$pCell		Cell to calculate
2256
	 * @return	mixed
2257
	 * @throws	Exception
2258
	 */
2259
	public function _calculateFormulaValue($formula, $cellID=null, PHPExcel_Cell $pCell = null) {
2260
//		echo '<b>'.$cellID.'</b><br />';
2261
		$cellValue = '';
2262
2263
		//	Basic validation that this is indeed a formula
2264
		//	We simply return the "cell value" (formula) if not
2265
		$formula = trim($formula);
2266
		if ($formula{0} != '=') return self::_wrapResult($formula);
2267
		$formula = ltrim(substr($formula,1));
2268
		if (!isset($formula{0})) return self::_wrapResult($formula);
2269
2270
		$wsTitle = "\x00Wrk";
2271
		if ($pCell !== NULL) {
2272
			$pCellParent = $pCell->getParent();
2273
			if ($pCellParent !== NULL) {
2274
				$wsTitle = $pCellParent->getTitle();
2275
			}
2276
		}
2277
		// Is calculation cacheing enabled?
2278
		if ($cellID !== NULL) {
2279
			if (self::$_calculationCacheEnabled) {
2280
				// Is the value present in calculation cache?
2281
//				echo 'Testing cache value<br />';
2282
				if (isset(self::$_calculationCache[$wsTitle][$cellID])) {
2283
//					echo 'Value is in cache<br />';
2284
					$this->_writeDebug('Testing cache value for cell '.$cellID);
2285
					//	Is cache still valid?
2286
					if ((microtime(true) - self::$_calculationCache[$wsTitle][$cellID]['time']) < self::$_calculationCacheExpirationTime) {
2287
//						echo 'Cache time is still valid<br />';
2288
						$this->_writeDebug('Retrieving value for '.$cellID.' from cache');
2289
						// Return the cached result
2290
						$returnValue = self::$_calculationCache[$wsTitle][$cellID]['data'];
2291
//						echo 'Retrieving data value of '.$returnValue.' for '.$cellID.' from cache<br />';
2292
						if (is_array($returnValue)) {
2293
							$returnValue = PHPExcel_Calculation_Functions::flattenArray($returnValue);
2294
							return array_shift($returnValue);
2295
						}
2296
						return $returnValue;
2297
					} else {
2298
//						echo 'Cache has expired<br />';
2299
						$this->_writeDebug('Cache value for '.$cellID.' has expired');
2300
						//	Clear the cache if it's no longer valid
2301
						unset(self::$_calculationCache[$wsTitle][$cellID]);
2302
					}
2303
				}
2304
			}
2305
		}
2306
2307
		if ((in_array($wsTitle.'!'.$cellID,$this->debugLogStack)) && ($wsTitle != "\x00Wrk")) {
2308
			if ($this->cyclicFormulaCount <= 0) {
2309
				return $this->_raiseFormulaError('Cyclic Reference in Formula');
2310 View Code Duplication
			} elseif (($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) &&
2311
					  ($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID)) {
2312
				return $cellValue;
2313
			} elseif ($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID) {
2314
				++$this->_cyclicFormulaCount;
2315
				if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) {
2316
					return $cellValue;
2317
				}
2318 View Code Duplication
			} elseif ($this->_cyclicFormulaCell == '') {
2319
				$this->_cyclicFormulaCell = $wsTitle.'!'.$cellID;
2320
				if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) {
2321
					return $cellValue;
2322
				}
2323
			}
2324
		}
2325
		$this->debugLogStack[] = $wsTitle.'!'.$cellID;
2326
		//	Parse the formula onto the token stack and calculate the value
2327
		$cellValue = $this->_processTokenStack($this->_parseFormula($formula, $pCell), $cellID, $pCell);
2328
		array_pop($this->debugLogStack);
2329
2330
		// Save to calculation cache
2331
		if ($cellID !== NULL) {
2332
			if (self::$_calculationCacheEnabled) {
2333
				self::$_calculationCache[$wsTitle][$cellID]['time'] = microtime(true);
2334
				self::$_calculationCache[$wsTitle][$cellID]['data'] = $cellValue;
2335
			}
2336
		}
2337
2338
		//	Return the calculated value
2339
		return $cellValue;
2340
	}	//	function _calculateFormulaValue()
2341
2342
2343
	/**
2344
	 * Ensure that paired matrix operands are both matrices and of the same size
2345
	 *
2346
	 * @param	mixed		&$operand1	First matrix operand
2347
	 * @param	mixed		&$operand2	Second matrix operand
2348
	 * @param	integer		$resize		Flag indicating whether the matrices should be resized to match
2349
	 *										and (if so), whether the smaller dimension should grow or the
2350
	 *										larger should shrink.
2351
	 *											0 = no resize
2352
	 *											1 = shrink to fit
2353
	 *											2 = extend to fit
2354
	 */
2355
	private static function _checkMatrixOperands(&$operand1,&$operand2,$resize = 1) {
2356
		//	Examine each of the two operands, and turn them into an array if they aren't one already
2357
		//	Note that this function should only be called if one or both of the operand is already an array
2358
		if (!is_array($operand1)) {
2359
			list($matrixRows,$matrixColumns) = self::_getMatrixDimensions($operand2);
2360
			$operand1 = array_fill(0,$matrixRows,array_fill(0,$matrixColumns,$operand1));
2361
			$resize = 0;
2362
		} elseif (!is_array($operand2)) {
2363
			list($matrixRows,$matrixColumns) = self::_getMatrixDimensions($operand1);
2364
			$operand2 = array_fill(0,$matrixRows,array_fill(0,$matrixColumns,$operand2));
2365
			$resize = 0;
2366
		}
2367
2368
		list($matrix1Rows,$matrix1Columns) = self::_getMatrixDimensions($operand1);
2369
		list($matrix2Rows,$matrix2Columns) = self::_getMatrixDimensions($operand2);
2370
		if (($matrix1Rows == $matrix2Columns) && ($matrix2Rows == $matrix1Columns)) {
2371
			$resize = 1;
2372
		}
2373
2374
		if ($resize == 2) {
2375
			//	Given two matrices of (potentially) unequal size, convert the smaller in each dimension to match the larger
2376
			self::_resizeMatricesExtend($operand1,$operand2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns);
2377
		} elseif ($resize == 1) {
2378
			//	Given two matrices of (potentially) unequal size, convert the larger in each dimension to match the smaller
2379
			self::_resizeMatricesShrink($operand1,$operand2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns);
2380
		}
2381
		return array( $matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns);
2382
	}	//	function _checkMatrixOperands()
2383
2384
2385
	/**
2386
	 * Read the dimensions of a matrix, and re-index it with straight numeric keys starting from row 0, column 0
2387
	 *
2388
	 * @param	mixed		&$matrix		matrix operand
2389
	 * @return	array		An array comprising the number of rows, and number of columns
2390
	 */
2391
	public static function _getMatrixDimensions(&$matrix) {
2392
		$matrixRows = count($matrix);
2393
		$matrixColumns = 0;
2394
		foreach($matrix as $rowKey => $rowValue) {
2395
			$matrixColumns = max(count($rowValue),$matrixColumns);
2396
			if (!is_array($rowValue)) {
2397
				$matrix[$rowKey] = array($rowValue);
2398
			} else {
2399
				$matrix[$rowKey] = array_values($rowValue);
2400
			}
2401
		}
2402
		$matrix = array_values($matrix);
2403
		return array($matrixRows,$matrixColumns);
2404
	}	//	function _getMatrixDimensions()
2405
2406
2407
	/**
2408
	 * Ensure that paired matrix operands are both matrices of the same size
2409
	 *
2410
	 * @param	mixed		&$matrix1	First matrix operand
2411
	 * @param	mixed		&$matrix2	Second matrix operand
2412
	 */
2413
	private static function _resizeMatricesShrink(&$matrix1,&$matrix2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns) {
2414 View Code Duplication
		if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) {
2415
			if ($matrix2Columns < $matrix1Columns) {
2416
				for ($i = 0; $i < $matrix1Rows; ++$i) {
2417
					for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) {
2418
						unset($matrix1[$i][$j]);
2419
					}
2420
				}
2421
			}
2422
			if ($matrix2Rows < $matrix1Rows) {
2423
				for ($i = $matrix2Rows; $i < $matrix1Rows; ++$i) {
2424
					unset($matrix1[$i]);
2425
				}
2426
			}
2427
		}
2428
2429 View Code Duplication
		if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) {
2430
			if ($matrix1Columns < $matrix2Columns) {
2431
				for ($i = 0; $i < $matrix2Rows; ++$i) {
2432
					for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
2433
						unset($matrix2[$i][$j]);
2434
					}
2435
				}
2436
			}
2437
			if ($matrix1Rows < $matrix2Rows) {
2438
				for ($i = $matrix1Rows; $i < $matrix2Rows; ++$i) {
2439
					unset($matrix2[$i]);
2440
				}
2441
			}
2442
		}
2443
	}	//	function _resizeMatricesShrink()
2444
2445
2446
	/**
2447
	 * Ensure that paired matrix operands are both matrices of the same size
2448
	 *
2449
	 * @param	mixed		&$matrix1	First matrix operand
2450
	 * @param	mixed		&$matrix2	Second matrix operand
2451
	 */
2452
	private static function _resizeMatricesExtend(&$matrix1,&$matrix2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns) {
2453 View Code Duplication
		if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) {
2454
			if ($matrix2Columns < $matrix1Columns) {
2455
				for ($i = 0; $i < $matrix2Rows; ++$i) {
2456
					$x = $matrix2[$i][$matrix2Columns-1];
2457
					for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) {
2458
						$matrix2[$i][$j] = $x;
2459
					}
2460
				}
2461
			}
2462
			if ($matrix2Rows < $matrix1Rows) {
2463
				$x = $matrix2[$matrix2Rows-1];
2464
				for ($i = 0; $i < $matrix1Rows; ++$i) {
2465
					$matrix2[$i] = $x;
2466
				}
2467
			}
2468
		}
2469
2470 View Code Duplication
		if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) {
2471
			if ($matrix1Columns < $matrix2Columns) {
2472
				for ($i = 0; $i < $matrix1Rows; ++$i) {
2473
					$x = $matrix1[$i][$matrix1Columns-1];
2474
					for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
2475
						$matrix1[$i][$j] = $x;
2476
					}
2477
				}
2478
			}
2479
			if ($matrix1Rows < $matrix2Rows) {
2480
				$x = $matrix1[$matrix1Rows-1];
2481
				for ($i = 0; $i < $matrix2Rows; ++$i) {
2482
					$matrix1[$i] = $x;
2483
				}
2484
			}
2485
		}
2486
	}	//	function _resizeMatricesExtend()
2487
2488
2489
	/**
2490
	 * Format details of an operand for display in the log (based on operand type)
2491
	 *
2492
	 * @param	mixed		$value	First matrix operand
2493
	 * @return	mixed
2494
	 */
2495
	private function _showValue($value) {
2496
		if ($this->writeDebugLog) {
2497
			$testArray = PHPExcel_Calculation_Functions::flattenArray($value);
2498
			if (count($testArray) == 1) {
2499
				$value = array_pop($testArray);
2500
			}
2501
2502
			if (is_array($value)) {
2503
				$returnMatrix = array();
2504
				$pad = $rpad = ', ';
2505
				foreach($value as $row) {
2506
					if (is_array($row)) {
2507
						$returnMatrix[] = implode($pad,array_map(array($this,'_showValue'),$row));
2508
						$rpad = '; ';
2509
					} else {
2510
						$returnMatrix[] = $this->_showValue($row);
2511
					}
2512
				}
2513
				return '{ '.implode($rpad,$returnMatrix).' }';
2514
			} elseif(is_string($value) && (trim($value,'"') == $value)) {
2515
				return '"'.$value.'"';
2516
			} elseif(is_bool($value)) {
2517
				return ($value) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE'];
2518
			}
2519
		}
2520
		return PHPExcel_Calculation_Functions::flattenSingleValue($value);
2521
	}	//	function _showValue()
2522
2523
2524
	/**
2525
	 * Format type and details of an operand for display in the log (based on operand type)
2526
	 *
2527
	 * @param	mixed		$value	First matrix operand
2528
	 * @return	mixed
2529
	 */
2530
	private function _showTypeDetails($value) {
2531
		if ($this->writeDebugLog) {
2532
			$testArray = PHPExcel_Calculation_Functions::flattenArray($value);
2533
			if (count($testArray) == 1) {
2534
				$value = array_pop($testArray);
2535
			}
2536
2537
			if ($value === NULL) {
2538
				return 'a NULL value';
2539
			} elseif (is_float($value)) {
2540
				$typeString = 'a floating point number';
2541
			} elseif(is_int($value)) {
2542
				$typeString = 'an integer number';
2543
			} elseif(is_bool($value)) {
2544
				$typeString = 'a boolean';
2545
			} elseif(is_array($value)) {
2546
				$typeString = 'a matrix';
2547
			} else {
2548
				if ($value == '') {
2549
					return 'an empty string';
2550
				} elseif ($value{0} == '#') {
2551
					return 'a '.$value.' error';
2552
				} else {
2553
					$typeString = 'a string';
2554
				}
2555
			}
2556
			return $typeString.' with a value of '.$this->_showValue($value);
2557
		}
2558
	}	//	function _showTypeDetails()
2559
2560
2561
	private static function _convertMatrixReferences($formula) {
2562
		static $matrixReplaceFrom = array('{',';','}');
2563
		static $matrixReplaceTo = array('MKMATRIX(MKMATRIX(','),MKMATRIX(','))');
2564
2565
		//	Convert any Excel matrix references to the MKMATRIX() function
2566
		if (strpos($formula,'{') !== false) {
2567
			//	If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
2568
			if (strpos($formula,'"') !== false) {
2569
				//	So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
2570
				//		the formula
2571
				$temp = explode('"',$formula);
2572
				//	Open and Closed counts used for trapping mismatched braces in the formula
2573
				$openCount = $closeCount = 0;
2574
				$i = false;
2575
				foreach($temp as &$value) {
2576
					//	Only count/replace in alternating array entries
2577
					if ($i = !$i) {
2578
						$openCount += substr_count($value,'{');
2579
						$closeCount += substr_count($value,'}');
2580
						$value = str_replace($matrixReplaceFrom,$matrixReplaceTo,$value);
2581
					}
2582
				}
2583
				unset($value);
2584
				//	Then rebuild the formula string
2585
				$formula = implode('"',$temp);
2586
			} else {
2587
				//	If there's no quoted strings, then we do a simple count/replace
2588
				$openCount = substr_count($formula,'{');
2589
				$closeCount = substr_count($formula,'}');
2590
				$formula = str_replace($matrixReplaceFrom,$matrixReplaceTo,$formula);
2591
			}
2592
			//	Trap for mismatched braces and trigger an appropriate error
2593
			if ($openCount < $closeCount) {
2594
				if ($openCount > 0) {
2595
					return $this->_raiseFormulaError("Formula Error: Mismatched matrix braces '}'");
0 ignored issues
show
Bug introduced by
The variable $this 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...
2596
				} else {
2597
					return $this->_raiseFormulaError("Formula Error: Unexpected '}' encountered");
2598
				}
2599
			} elseif ($openCount > $closeCount) {
2600
				if ($closeCount > 0) {
2601
					return $this->_raiseFormulaError("Formula Error: Mismatched matrix braces '{'");
2602
				} else {
2603
					return $this->_raiseFormulaError("Formula Error: Unexpected '{' encountered");
2604
				}
2605
			}
2606
		}
2607
2608
		return $formula;
2609
	}	//	function _convertMatrixReferences()
2610
2611
2612
	private static function _mkMatrix() {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2613
		return func_get_args();
2614
	}	//	function _mkMatrix()
2615
2616
2617
	// Convert infix to postfix notation
2618
	private function _parseFormula($formula, PHPExcel_Cell $pCell = null) {
2619
		if (($formula = self::_convertMatrixReferences(trim($formula))) === false) {
2620
			return FALSE;
2621
		}
2622
2623
		//	If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent worksheet),
2624
		//		so we store the parent worksheet so that we can re-attach it when necessary
2625
		$pCellParent = ($pCell !== NULL) ? $pCell->getParent() : NULL;
2626
2627
		//	Binary Operators
2628
		//	These operators always work on two values
2629
		//	Array key is the operator, the value indicates whether this is a left or right associative operator
2630
		$operatorAssociativity	= array('^' => 0,															//	Exponentiation
2631
										'*' => 0, '/' => 0, 												//	Multiplication and Division
2632
										'+' => 0, '-' => 0,													//	Addition and Subtraction
2633
										'&' => 0,															//	Concatenation
2634
										'|' => 0, ':' => 0,													//	Intersect and Range
2635
										'>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0		//	Comparison
2636
								 	  );
2637
		//	Comparison (Boolean) Operators
2638
		//	These operators work on two values, but always return a boolean result
2639
		$comparisonOperators	= array('>' => true, '<' => true, '=' => true, '>=' => true, '<=' => true, '<>' => true);
2640
2641
		//	Operator Precedence
2642
		//	This list includes all valid operators, whether binary (including boolean) or unary (such as %)
2643
		//	Array key is the operator, the value is its precedence
2644
		$operatorPrecedence	= array(':' => 8,																//	Range
2645
									'|' => 7,																//	Intersect
2646
									'~' => 6,																//	Negation
2647
									'%' => 5,																//	Percentage
2648
									'^' => 4,																//	Exponentiation
2649
									'*' => 3, '/' => 3, 													//	Multiplication and Division
2650
									'+' => 2, '-' => 2,														//	Addition and Subtraction
2651
									'&' => 1,																//	Concatenation
2652
									'>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0			//	Comparison
2653
								   );
2654
2655
		$regexpMatchString = '/^('.self::CALCULATION_REGEXP_FUNCTION.
2656
							   '|'.self::CALCULATION_REGEXP_NUMBER.
2657
							   '|'.self::CALCULATION_REGEXP_STRING.
2658
							   '|'.self::CALCULATION_REGEXP_OPENBRACE.
2659
							   '|'.self::CALCULATION_REGEXP_CELLREF.
2660
							   '|'.self::CALCULATION_REGEXP_NAMEDRANGE.
2661
							   '|'.self::CALCULATION_REGEXP_ERROR.
2662
							 ')/si';
2663
2664
		//	Start with initialisation
2665
		$index = 0;
2666
		$stack = new PHPExcel_Token_Stack;
2667
		$output = array();
2668
		$expectingOperator = false;					//	We use this test in syntax-checking the expression to determine when a
2669
													//		- is a negation or + is a positive operator rather than an operation
2670
		$expectingOperand = false;					//	We use this test in syntax-checking the expression to determine whether an operand
2671
													//		should be null in a function call
2672
		//	The guts of the lexical parser
2673
		//	Loop through the formula extracting each operator and operand in turn
2674
		while(true) {
2675
//			echo 'Assessing Expression <b>'.substr($formula, $index).'</b><br />';
2676
			$opCharacter = $formula{$index};	//	Get the first character of the value at the current index position
2677
//			echo 'Initial character of expression block is '.$opCharacter.'<br />';
2678
			if ((isset($comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset($comparisonOperators[$formula{$index+1}]))) {
2679
				$opCharacter .= $formula{++$index};
2680
//				echo 'Initial character of expression block is comparison operator '.$opCharacter.'<br />';
2681
			}
2682
2683
			//	Find out if we're currently at the beginning of a number, variable, cell reference, function, parenthesis or operand
2684
			$isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match);
2685
//			echo '$isOperandOrFunction is '.(($isOperandOrFunction) ? 'True' : 'False').'<br />';
2686
//			var_dump($match);
2687
2688
			if ($opCharacter == '-' && !$expectingOperator) {				//	Is it a negation instead of a minus?
2689
//				echo 'Element is a Negation operator<br />';
2690
				$stack->push('Unary Operator','~');							//	Put a negation on the stack
2691
				++$index;													//		and drop the negation symbol
2692
			} elseif ($opCharacter == '%' && $expectingOperator) {
2693
//				echo 'Element is a Percentage operator<br />';
2694
				$stack->push('Unary Operator','%');							//	Put a percentage on the stack
2695
				++$index;
2696
			} elseif ($opCharacter == '+' && !$expectingOperator) {			//	Positive (unary plus rather than binary operator plus) can be discarded?
2697
//				echo 'Element is a Positive number, not Plus operator<br />';
2698
				++$index;													//	Drop the redundant plus symbol
2699
			} elseif ((($opCharacter == '~') || ($opCharacter == '|')) && (!$isOperandOrFunction)) {	//	We have to explicitly deny a tilde or pipe, because they are legal
2700
				return $this->_raiseFormulaError("Formula Error: Illegal character '~'");				//		on the stack but not in the input expression
2701
2702
			} elseif ((isset(self::$_operators[$opCharacter]) or $isOperandOrFunction) && $expectingOperator) {	//	Are we putting an operator on the stack?
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...
2703
//				echo 'Element with value '.$opCharacter.' is an Operator<br />';
2704 View Code Duplication
				while($stack->count() > 0 &&
2705
					($o2 = $stack->last()) &&
2706
					isset(self::$_operators[$o2['value']]) &&
2707
					@($operatorAssociativity[$opCharacter] ? $operatorPrecedence[$opCharacter] < $operatorPrecedence[$o2['value']] : $operatorPrecedence[$opCharacter] <= $operatorPrecedence[$o2['value']])) {
2708
					$output[] = $stack->pop();								//	Swap operands and higher precedence operators from the stack to the output
2709
				}
2710
				$stack->push('Binary Operator',$opCharacter);	//	Finally put our current operator onto the stack
2711
				++$index;
2712
				$expectingOperator = false;
2713
2714
			} elseif ($opCharacter == ')' && $expectingOperator) {			//	Are we expecting to close a parenthesis?
2715
//				echo 'Element is a Closing bracket<br />';
2716
				$expectingOperand = false;
2717 View Code Duplication
				while (($o2 = $stack->pop()) && $o2['value'] != '(') {		//	Pop off the stack back to the last (
2718
					if ($o2 === NULL) return $this->_raiseFormulaError('Formula Error: Unexpected closing brace ")"');
2719
					else $output[] = $o2;
2720
				}
2721
				$d = $stack->last(2);
2722
				if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches)) {	//	Did this parenthesis just close a function?
2723
					$functionName = $matches[1];										//	Get the function name
2724
//					echo 'Closed Function is '.$functionName.'<br />';
2725
					$d = $stack->pop();
2726
					$argumentCount = $d['value'];		//	See how many arguments there were (argument count is the next value stored on the stack)
2727
//					if ($argumentCount == 0) {
2728
//						echo 'With no arguments<br />';
2729
//					} elseif ($argumentCount == 1) {
2730
//						echo 'With 1 argument<br />';
2731
//					} else {
2732
//						echo 'With '.$argumentCount.' arguments<br />';
2733
//					}
2734
					$output[] = $d;						//	Dump the argument count on the output
2735
					$output[] = $stack->pop();			//	Pop the function and push onto the output
2736
					if (isset(self::$_controlFunctions[$functionName])) {
2737
//						echo 'Built-in function '.$functionName.'<br />';
2738
						$expectedArgumentCount = self::$_controlFunctions[$functionName]['argumentCount'];
2739
						$functionCall = self::$_controlFunctions[$functionName]['functionCall'];
2740
					} elseif (isset(self::$_PHPExcelFunctions[$functionName])) {
2741
//						echo 'PHPExcel function '.$functionName.'<br />';
2742
						$expectedArgumentCount = self::$_PHPExcelFunctions[$functionName]['argumentCount'];
2743
						$functionCall = self::$_PHPExcelFunctions[$functionName]['functionCall'];
2744
					} else {	// did we somehow push a non-function on the stack? this should never happen
2745
						return $this->_raiseFormulaError("Formula Error: Internal error, non-function on stack");
2746
					}
2747
					//	Check the argument count
2748
					$argumentCountError = false;
2749
					if (is_numeric($expectedArgumentCount)) {
2750
						if ($expectedArgumentCount < 0) {
2751
//							echo '$expectedArgumentCount is between 0 and '.abs($expectedArgumentCount).'<br />';
2752
							if ($argumentCount > abs($expectedArgumentCount)) {
2753
								$argumentCountError = true;
2754
								$expectedArgumentCountString = 'no more than '.abs($expectedArgumentCount);
2755
							}
2756
						} else {
2757
//							echo '$expectedArgumentCount is numeric '.$expectedArgumentCount.'<br />';
2758
							if ($argumentCount != $expectedArgumentCount) {
2759
								$argumentCountError = true;
2760
								$expectedArgumentCountString = $expectedArgumentCount;
2761
							}
2762
						}
2763
					} elseif ($expectedArgumentCount != '*') {
2764
						$isOperandOrFunction = preg_match('/(\d*)([-+,])(\d*)/',$expectedArgumentCount,$argMatch);
2765
//						print_r($argMatch);
2766
//						echo '<br />';
2767
						switch ($argMatch[2]) {
2768
							case '+' :
2769
								if ($argumentCount < $argMatch[1]) {
2770
									$argumentCountError = true;
2771
									$expectedArgumentCountString = $argMatch[1].' or more ';
2772
								}
2773
								break;
2774 View Code Duplication
							case '-' :
2775
								if (($argumentCount < $argMatch[1]) || ($argumentCount > $argMatch[3])) {
2776
									$argumentCountError = true;
2777
									$expectedArgumentCountString = 'between '.$argMatch[1].' and '.$argMatch[3];
2778
								}
2779
								break;
2780 View Code Duplication
							case ',' :
2781
								if (($argumentCount != $argMatch[1]) && ($argumentCount != $argMatch[3])) {
2782
									$argumentCountError = true;
2783
									$expectedArgumentCountString = 'either '.$argMatch[1].' or '.$argMatch[3];
2784
								}
2785
								break;
2786
						}
2787
					}
2788
					if ($argumentCountError) {
2789
						return $this->_raiseFormulaError("Formula Error: Wrong number of arguments for $functionName() function: $argumentCount given, ".$expectedArgumentCountString." expected");
0 ignored issues
show
Bug introduced by
The variable $expectedArgumentCountString 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...
2790
					}
2791
				}
2792
				++$index;
2793
2794
			} elseif ($opCharacter == ',') {			//	Is this the separator for function arguments?
2795
//				echo 'Element is a Function argument separator<br />';
2796 View Code Duplication
				while (($o2 = $stack->pop()) && $o2['value'] != '(') {		//	Pop off the stack back to the last (
2797
					if ($o2 === NULL) return $this->_raiseFormulaError("Formula Error: Unexpected ,");
2798
					else $output[] = $o2;	// pop the argument expression stuff and push onto the output
2799
				}
2800
				//	If we've a comma when we're expecting an operand, then what we actually have is a null operand;
2801
				//		so push a null onto the stack
2802
				if (($expectingOperand) || (!$expectingOperator)) {
2803
					$output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => null);
2804
				}
2805
				// make sure there was a function
2806
				$d = $stack->last(2);
2807
				if (!preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches))
2808
					return $this->_raiseFormulaError("Formula Error: Unexpected ,");
2809
				$d = $stack->pop();
2810
				$stack->push($d['type'],++$d['value'],$d['reference']);	// increment the argument count
2811
				$stack->push('Brace', '(');	// put the ( back on, we'll need to pop back to it again
2812
				$expectingOperator = false;
2813
				$expectingOperand = true;
2814
				++$index;
2815
2816
			} elseif ($opCharacter == '(' && !$expectingOperator) {
2817
//				echo 'Element is an Opening Bracket<br />';
2818
				$stack->push('Brace', '(');
2819
				++$index;
2820
2821
			} elseif ($isOperandOrFunction && !$expectingOperator) {	// do we now have a function/variable/number?
2822
				$expectingOperator = true;
2823
				$expectingOperand = false;
2824
				$val = $match[1];
2825
				$length = strlen($val);
2826
//				echo 'Element with value '.$val.' is an Operand, Variable, Constant, String, Number, Cell Reference or Function<br />';
2827
2828
				if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $val, $matches)) {
2829
					$val = preg_replace('/\s/','',$val);
2830
//					echo 'Element '.$val.' is a Function<br />';
2831
					if (isset(self::$_PHPExcelFunctions[strtoupper($matches[1])]) || isset(self::$_controlFunctions[strtoupper($matches[1])])) {	// it's a function
2832
						$stack->push('Function', strtoupper($val));
2833
						$ax = preg_match('/^\s*(\s*\))/i', substr($formula, $index+$length), $amatch);
2834
						if ($ax) {
2835
							$stack->push('Operand Count for Function '.strtoupper($val).')', 0);
2836
							$expectingOperator = true;
2837
						} else {
2838
							$stack->push('Operand Count for Function '.strtoupper($val).')', 1);
2839
							$expectingOperator = false;
2840
						}
2841
						$stack->push('Brace', '(');
2842
					} else {	// it's a var w/ implicit multiplication
2843
						$output[] = array('type' => 'Value', 'value' => $matches[1], 'reference' => null);
2844
					}
2845
				} elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $val, $matches)) {
2846
//					echo 'Element '.$val.' is a Cell reference<br />';
2847
					//	Watch for this case-change when modifying to allow cell references in different worksheets...
2848
					//	Should only be applied to the actual cell column, not the worksheet name
2849
2850
					//	If the last entry on the stack was a : operator, then we have a cell range reference
2851
					$testPrevOp = $stack->last(1);
2852
					if ($testPrevOp['value'] == ':') {
2853
						//	If we have a worksheet reference, then we're playing with a 3D reference
2854
						if ($matches[2] == '') {
2855
							//	Otherwise, we 'inherit' the worksheet reference from the start cell reference
2856
							//	The start of the cell range reference should be the last entry in $output
2857
							$startCellRef = $output[count($output)-1]['value'];
2858
							preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $startCellRef, $startMatches);
2859
							if ($startMatches[2] > '') {
2860
								$val = $startMatches[2].'!'.$val;
2861
							}
2862
						} else {
2863
							return $this->_raiseFormulaError("3D Range references are not yet supported");
2864
						}
2865
					}
2866
2867
					$output[] = array('type' => 'Cell Reference', 'value' => $val, 'reference' => $val);
2868
//					$expectingOperator = false;
2869
				} else {	// it's a variable, constant, string, number or boolean
2870
//					echo 'Element is a Variable, Constant, String, Number or Boolean<br />';
2871
					//	If the last entry on the stack was a : operator, then we may have a row or column range reference
2872
					$testPrevOp = $stack->last(1);
2873
					if ($testPrevOp['value'] == ':') {
2874
						$startRowColRef = $output[count($output)-1]['value'];
2875
						$rangeWS1 = '';
2876
						if (strpos('!',$startRowColRef) !== false) {
2877
							list($rangeWS1,$startRowColRef) = explode('!',$startRowColRef);
2878
						}
2879
						if ($rangeWS1 != '') $rangeWS1 .= '!';
2880
						$rangeWS2 = $rangeWS1;
2881
						if (strpos('!',$val) !== false) {
2882
							list($rangeWS2,$val) = explode('!',$val);
2883
						}
2884
						if ($rangeWS2 != '') $rangeWS2 .= '!';
2885
						if ((is_integer($startRowColRef)) && (ctype_digit($val)) &&
2886
							($startRowColRef <= 1048576) && ($val <= 1048576)) {
2887
							//	Row range
2888
							$endRowColRef = ($pCellParent !== NULL) ? $pCellParent->getHighestColumn() : 'XFD';	//	Max 16,384 columns for Excel2007
2889
							$output[count($output)-1]['value'] = $rangeWS1.'A'.$startRowColRef;
2890
							$val = $rangeWS2.$endRowColRef.$val;
2891
						} elseif ((ctype_alpha($startRowColRef)) && (ctype_alpha($val)) &&
2892
							(strlen($startRowColRef) <= 3) && (strlen($val) <= 3)) {
2893
							//	Column range
2894
							$endRowColRef = ($pCellParent !== NULL) ? $pCellParent->getHighestRow() : 1048576;		//	Max 1,048,576 rows for Excel2007
2895
							$output[count($output)-1]['value'] = $rangeWS1.strtoupper($startRowColRef).'1';
2896
							$val = $rangeWS2.$val.$endRowColRef;
2897
						}
2898
					}
2899
2900
					$localeConstant = false;
2901
					if ($opCharacter == '"') {
2902
//						echo 'Element is a String<br />';
2903
						//	UnEscape any quotes within the string
2904
						$val = self::_wrapResult(str_replace('""','"',self::_unwrapResult($val)));
2905
					} elseif (is_numeric($val)) {
2906
//						echo 'Element is a Number<br />';
2907
						if ((strpos($val,'.') !== false) || (stripos($val,'e') !== false) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) {
2908
//							echo 'Casting '.$val.' to float<br />';
2909
							$val = (float) $val;
2910
						} else {
2911
//							echo 'Casting '.$val.' to integer<br />';
2912
							$val = (integer) $val;
2913
						}
2914
					} elseif (isset(self::$_ExcelConstants[trim(strtoupper($val))])) {
2915
						$excelConstant = trim(strtoupper($val));
2916
//						echo 'Element '.$excelConstant.' is an Excel Constant<br />';
2917
						$val = self::$_ExcelConstants[$excelConstant];
2918
					} elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$_localeBoolean)) !== false) {
2919
//						echo 'Element '.$localeConstant.' is an Excel Constant<br />';
2920
						$val = self::$_ExcelConstants[$localeConstant];
2921
					}
2922
					$details = array('type' => 'Value', 'value' => $val, 'reference' => null);
2923
					if ($localeConstant) { $details['localeValue'] = $localeConstant; }
2924
					$output[] = $details;
2925
				}
2926
				$index += $length;
2927
2928
			} elseif ($opCharacter == '$') {	// absolute row or column range
2929
				++$index;
2930
			} elseif ($opCharacter == ')') {	// miscellaneous error checking
2931
				if ($expectingOperand) {
2932
					$output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => null);
2933
					$expectingOperand = false;
2934
					$expectingOperator = true;
2935
				} else {
2936
					return $this->_raiseFormulaError("Formula Error: Unexpected ')'");
2937
				}
2938
			} elseif (isset(self::$_operators[$opCharacter]) && !$expectingOperator) {
2939
				return $this->_raiseFormulaError("Formula Error: Unexpected operator '$opCharacter'");
2940
			} else {	// I don't even want to know what you did to get here
2941
				return $this->_raiseFormulaError("Formula Error: An unexpected error occured");
2942
			}
2943
			//	Test for end of formula string
2944
			if ($index == strlen($formula)) {
2945
				//	Did we end with an operator?.
2946
				//	Only valid for the % unary operator
2947
				if ((isset(self::$_operators[$opCharacter])) && ($opCharacter != '%')) {
2948
					return $this->_raiseFormulaError("Formula Error: Operator '$opCharacter' has no operands");
2949
				} else {
2950
					break;
2951
				}
2952
			}
2953
			//	Ignore white space
2954
			while (($formula{$index} == "\n") || ($formula{$index} == "\r")) {
2955
				++$index;
2956
			}
2957
			if ($formula{$index} == ' ') {
2958
				while ($formula{$index} == ' ') {
2959
					++$index;
2960
				}
2961
				//	If we're expecting an operator, but only have a space between the previous and next operands (and both are
2962
				//		Cell References) then we have an INTERSECTION operator
2963
//				echo 'Possible Intersect Operator<br />';
2964
				if (($expectingOperator) && (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'.*/Ui', substr($formula, $index), $match)) &&
2965
					($output[count($output)-1]['type'] == 'Cell Reference')) {
2966
//					echo 'Element is an Intersect Operator<br />';
2967 View Code Duplication
					while($stack->count() > 0 &&
2968
						($o2 = $stack->last()) &&
2969
						isset(self::$_operators[$o2['value']]) &&
2970
						@($operatorAssociativity[$opCharacter] ? $operatorPrecedence[$opCharacter] < $operatorPrecedence[$o2['value']] : $operatorPrecedence[$opCharacter] <= $operatorPrecedence[$o2['value']])) {
2971
						$output[] = $stack->pop();								//	Swap operands and higher precedence operators from the stack to the output
2972
					}
2973
					$stack->push('Binary Operator','|');	//	Put an Intersect Operator on the stack
2974
					$expectingOperator = false;
2975
				}
2976
			}
2977
		}
2978
2979 View Code Duplication
		while (($op = $stack->pop()) !== NULL) {	// pop everything off the stack and push onto output
2980
			if ((is_array($opCharacter) && $opCharacter['value'] == '(') || ($opCharacter === '('))
0 ignored issues
show
Bug introduced by
The variable $opCharacter 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...
2981
				return $this->_raiseFormulaError("Formula Error: Expecting ')'");	// if there are any opening braces on the stack, then braces were unbalanced
2982
			$output[] = $op;
2983
		}
2984
		return $output;
2985
	}	//	function _parseFormula()
2986
2987
2988
	private static function _dataTestReference(&$operandData)
2989
	{
2990
		$operand = $operandData['value'];
2991
		if (($operandData['reference'] === NULL) && (is_array($operand))) {
2992
			$rKeys = array_keys($operand);
2993
			$rowKey = array_shift($rKeys);
2994
			$cKeys = array_keys(array_keys($operand[$rowKey]));
2995
			$colKey = array_shift($cKeys);
2996
			if (ctype_upper($colKey)) {
2997
				$operandData['reference'] = $colKey.$rowKey;
2998
			}
2999
		}
3000
		return $operand;
3001
	}
3002
3003
	// evaluate postfix notation
3004
	private function _processTokenStack($tokens, $cellID = null, PHPExcel_Cell $pCell = null) {
3005
		if ($tokens == false) return false;
3006
3007
		//	If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent worksheet),
3008
		//		so we store the parent worksheet so that we can re-attach it when necessary
3009
		$pCellParent = ($pCell !== NULL) ? $pCell->getParent() : null;
3010
		$stack = new PHPExcel_Token_Stack;
3011
3012
		//	Loop through each token in turn
3013
		foreach ($tokens as $tokenData) {
3014
//			print_r($tokenData);
3015
//			echo '<br />';
3016
			$token = $tokenData['value'];
3017
//			echo '<b>Token is '.$token.'</b><br />';
3018
			// if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
3019
			if (isset(self::$_binaryOperators[$token])) {
3020
//				echo 'Token is a binary operator<br />';
3021
				//	We must have two operands, error if we don't
3022
				if (($operand2Data = $stack->pop()) === NULL) return $this->_raiseFormulaError('Internal error - Operand value missing from stack');
3023
				if (($operand1Data = $stack->pop()) === NULL) return $this->_raiseFormulaError('Internal error - Operand value missing from stack');
3024
3025
				$operand1 = self::_dataTestReference($operand1Data);
3026
				$operand2 = self::_dataTestReference($operand2Data);
3027
3028
				//	Log what we're doing
3029
				if ($token == ':') {
3030
					$this->_writeDebug('Evaluating Range '.$this->_showValue($operand1Data['reference']).$token.$this->_showValue($operand2Data['reference']));
3031
				} else {
3032
					$this->_writeDebug('Evaluating '.$this->_showValue($operand1).' '.$token.' '.$this->_showValue($operand2));
3033
				}
3034
3035
				//	Process the operation in the appropriate manner
3036
				switch ($token) {
3037
					//	Comparison (Boolean) Operators
3038
					case '>'	:			//	Greater than
3039
					case '<'	:			//	Less than
3040
					case '>='	:			//	Greater than or Equal to
3041
					case '<='	:			//	Less than or Equal to
3042
					case '='	:			//	Equality
3043
					case '<>'	:			//	Inequality
3044
						$this->_executeBinaryComparisonOperation($cellID,$operand1,$operand2,$token,$stack);
3045
						break;
3046
					//	Binary Operators
3047
					case ':'	:			//	Range
3048
						$sheet1 = $sheet2 = '';
3049 View Code Duplication
						if (strpos($operand1Data['reference'],'!') !== false) {
3050
							list($sheet1,$operand1Data['reference']) = explode('!',$operand1Data['reference']);
3051
						} else {
3052
							$sheet1 = ($pCellParent !== NULL) ? $pCellParent->getTitle() : '';
3053
						}
3054 View Code Duplication
						if (strpos($operand2Data['reference'],'!') !== false) {
3055
							list($sheet2,$operand2Data['reference']) = explode('!',$operand2Data['reference']);
3056
						} else {
3057
							$sheet2 = $sheet1;
3058
						}
3059
						if ($sheet1 == $sheet2) {
3060 View Code Duplication
							if ($operand1Data['reference'] === NULL) {
3061
								if ((trim($operand1Data['value']) != '') && (is_numeric($operand1Data['value']))) {
3062
									$operand1Data['reference'] = $pCell->getColumn().$operand1Data['value'];
0 ignored issues
show
Bug introduced by
It seems like $pCell is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
3063
								} elseif (trim($operand1Data['reference']) == '') {
3064
									$operand1Data['reference'] = $pCell->getCoordinate();
3065
								} else {
3066
									$operand1Data['reference'] = $operand1Data['value'].$pCell->getRow();
3067
								}
3068
							}
3069 View Code Duplication
							if ($operand2Data['reference'] === NULL) {
3070
								if ((trim($operand2Data['value']) != '') && (is_numeric($operand2Data['value']))) {
3071
									$operand2Data['reference'] = $pCell->getColumn().$operand2Data['value'];
3072
								} elseif (trim($operand2Data['reference']) == '') {
3073
									$operand2Data['reference'] = $pCell->getCoordinate();
3074
								} else {
3075
									$operand2Data['reference'] = $operand2Data['value'].$pCell->getRow();
3076
								}
3077
							}
3078
3079
							$oData = array_merge(explode(':',$operand1Data['reference']),explode(':',$operand2Data['reference']));
3080
							$oCol = $oRow = array();
3081
							foreach($oData as $oDatum) {
3082
								$oCR = PHPExcel_Cell::coordinateFromString($oDatum);
3083
								$oCol[] = PHPExcel_Cell::columnIndexFromString($oCR[0]) - 1;
3084
								$oRow[] = $oCR[1];
3085
							}
3086
							$cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow);
3087 View Code Duplication
							if ($pCellParent !== NULL) {
3088
								$cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($sheet1), false);
3089
							} else {
3090
								return $this->_raiseFormulaError('Unable to access Cell Reference');
3091
							}
3092
							$stack->push('Cell Reference',$cellValue,$cellRef);
3093
						} else {
3094
							$stack->push('Error',PHPExcel_Calculation_Functions::REF(),null);
3095
						}
3096
3097
						break;
3098
					case '+'	:			//	Addition
3099
						$this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'plusEquals',$stack);
3100
						break;
3101
					case '-'	:			//	Subtraction
3102
						$this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'minusEquals',$stack);
3103
						break;
3104
					case '*'	:			//	Multiplication
3105
						$this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'arrayTimesEquals',$stack);
3106
						break;
3107
					case '/'	:			//	Division
3108
						$this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'arrayRightDivide',$stack);
3109
						break;
3110
					case '^'	:			//	Exponential
3111
						$this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'power',$stack);
3112
						break;
3113
					case '&'	:			//	Concatenation
3114
						//	If either of the operands is a matrix, we need to treat them both as matrices
3115
						//		(converting the other operand to a matrix if need be); then perform the required
3116
						//		matrix operation
3117
						if (is_bool($operand1)) {
3118
							$operand1 = ($operand1) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE'];
3119
						}
3120
						if (is_bool($operand2)) {
3121
							$operand2 = ($operand2) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE'];
3122
						}
3123
						if ((is_array($operand1)) || (is_array($operand2))) {
3124
							//	Ensure that both operands are arrays/matrices
3125
							self::_checkMatrixOperands($operand1,$operand2,2);
3126
							try {
3127
								//	Convert operand 1 from a PHP array to a matrix
3128
								$matrix = new PHPExcel_Shared_JAMA_Matrix($operand1);
3129
								//	Perform the required operation against the operand 1 matrix, passing in operand 2
3130
								$matrixResult = $matrix->concat($operand2);
3131
								$result = $matrixResult->getArray();
3132
							} catch (Exception $ex) {
3133
								$this->_writeDebug('JAMA Matrix Exception: '.$ex->getMessage());
3134
								$result = '#VALUE!';
3135
							}
3136
						} else {
3137
							$result = '"'.str_replace('""','"',self::_unwrapResult($operand1,'"').self::_unwrapResult($operand2,'"')).'"';
3138
						}
3139
						$this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result));
3140
						$stack->push('Value',$result);
3141
						break;
3142
					case '|'	:			//	Intersect
3143
						$rowIntersect = array_intersect_key($operand1,$operand2);
3144
						$cellIntersect = $oCol = $oRow = array();
3145
						foreach(array_keys($rowIntersect) as $row) {
3146
							$oRow[] = $row;
3147
							foreach($rowIntersect[$row] as $col => $data) {
3148
								$oCol[] = PHPExcel_Cell::columnIndexFromString($col) - 1;
3149
								$cellIntersect[$row] = array_intersect_key($operand1[$row],$operand2[$row]);
3150
							}
3151
						}
3152
						$cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow);
3153
						$this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($cellIntersect));
3154
						$stack->push('Value',$cellIntersect,$cellRef);
3155
						break;
3156
				}
3157
3158
			// if the token is a unary operator, pop one value off the stack, do the operation, and push it back on
3159
			} elseif (($token === '~') || ($token === '%')) {
3160
//				echo 'Token is a unary operator<br />';
3161
				if (($arg = $stack->pop()) === NULL) return $this->_raiseFormulaError('Internal error - Operand value missing from stack');
3162
				$arg = $arg['value'];
3163
				if ($token === '~') {
3164
//					echo 'Token is a negation operator<br />';
3165
					$this->_writeDebug('Evaluating Negation of '.$this->_showValue($arg));
3166
					$multiplier = -1;
3167
				} else {
3168
//					echo 'Token is a percentile operator<br />';
3169
					$this->_writeDebug('Evaluating Percentile of '.$this->_showValue($arg));
3170
					$multiplier = 0.01;
3171
				}
3172
				if (is_array($arg)) {
3173
					self::_checkMatrixOperands($arg,$multiplier,2);
3174
					try {
3175
						$matrix1 = new PHPExcel_Shared_JAMA_Matrix($arg);
3176
						$matrixResult = $matrix1->arrayTimesEquals($multiplier);
3177
						$result = $matrixResult->getArray();
3178
					} catch (Exception $ex) {
3179
						$this->_writeDebug('JAMA Matrix Exception: '.$ex->getMessage());
3180
						$result = '#VALUE!';
3181
					}
3182
					$this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result));
3183
					$stack->push('Value',$result);
3184
				} else {
3185
					$this->_executeNumericBinaryOperation($cellID,$multiplier,$arg,'*','arrayTimesEquals',$stack);
3186
				}
3187
3188
			} elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $token, $matches)) {
3189
				$cellRef = null;
3190
//				echo 'Element '.$token.' is a Cell reference<br />';
3191
				if (isset($matches[8])) {
3192
//					echo 'Reference is a Range of cells<br />';
3193
					if ($pCell === NULL) {
3194
//						We can't access the range, so return a REF error
3195
						$cellValue = PHPExcel_Calculation_Functions::REF();
3196
					} else {
3197
						$cellRef = $matches[6].$matches[7].':'.$matches[9].$matches[10];
3198
						if ($matches[2] > '') {
3199
							$matches[2] = trim($matches[2],"\"'");
3200 View Code Duplication
							if ((strpos($matches[2],'[') !== false) || (strpos($matches[2],']') !== false)) {
3201
								//	It's a Reference to an external workbook (not currently supported)
3202
								return $this->_raiseFormulaError('Unable to access External Workbook');
3203
							}
3204
							$matches[2] = trim($matches[2],"\"'");
3205
//							echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'<br />';
3206
							$this->_writeDebug('Evaluating Cell Range '.$cellRef.' in worksheet '.$matches[2]);
3207 View Code Duplication
							if ($pCellParent !== NULL) {
3208
								$cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($matches[2]), false);
3209
							} else {
3210
								return $this->_raiseFormulaError('Unable to access Cell Reference');
3211
							}
3212
							$this->_writeDebug('Evaluation Result for cells '.$cellRef.' in worksheet '.$matches[2].' is '.$this->_showTypeDetails($cellValue));
3213
//							$cellRef = $matches[2].'!'.$cellRef;
3214
						} else {
3215
//							echo '$cellRef='.$cellRef.' in current worksheet<br />';
3216
							$this->_writeDebug('Evaluating Cell Range '.$cellRef.' in current worksheet');
3217
							if ($pCellParent !== NULL) {
3218
								$cellValue = $this->extractCellRange($cellRef, $pCellParent, false);
3219
							} else {
3220
								return $this->_raiseFormulaError('Unable to access Cell Reference');
3221
							}
3222
							$this->_writeDebug('Evaluation Result for cells '.$cellRef.' is '.$this->_showTypeDetails($cellValue));
3223
						}
3224
					}
3225
				} else {
3226
//					echo 'Reference is a single Cell<br />';
3227
					if ($pCell === NULL) {
3228
//						We can't access the cell, so return a REF error
3229
						$cellValue = PHPExcel_Calculation_Functions::REF();
3230
					} else {
3231
						$cellRef = $matches[6].$matches[7];
3232
						if ($matches[2] > '') {
3233
							$matches[2] = trim($matches[2],"\"'");
3234 View Code Duplication
							if ((strpos($matches[2],'[') !== false) || (strpos($matches[2],']') !== false)) {
3235
								//	It's a Reference to an external workbook (not currently supported)
3236
								return $this->_raiseFormulaError('Unable to access External Workbook');
3237
							}
3238
//							echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'<br />';
3239
							$this->_writeDebug('Evaluating Cell '.$cellRef.' in worksheet '.$matches[2]);
3240
							if ($pCellParent !== NULL) {
3241
								if ($pCellParent->getParent()->getSheetByName($matches[2])->cellExists($cellRef)) {
3242
									$cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($matches[2]), false);
3243
									$pCell->attach($pCellParent);
3244
								} else {
3245
									$cellValue = null;
3246
								}
3247
							} else {
3248
								return $this->_raiseFormulaError('Unable to access Cell Reference');
3249
							}
3250
							$this->_writeDebug('Evaluation Result for cell '.$cellRef.' in worksheet '.$matches[2].' is '.$this->_showTypeDetails($cellValue));
3251
//							$cellRef = $matches[2].'!'.$cellRef;
3252
						} else {
3253
//							echo '$cellRef='.$cellRef.' in current worksheet<br />';
3254
							$this->_writeDebug('Evaluating Cell '.$cellRef.' in current worksheet');
3255
							if ($pCellParent->cellExists($cellRef)) {
3256
								$cellValue = $this->extractCellRange($cellRef, $pCellParent, false);
3257
								$pCell->attach($pCellParent);
3258
							} else {
3259
								$cellValue = null;
3260
							}
3261
							$this->_writeDebug('Evaluation Result for cell '.$cellRef.' is '.$this->_showTypeDetails($cellValue));
3262
						}
3263
					}
3264
				}
3265
				$stack->push('Value',$cellValue,$cellRef);
3266
3267
			// if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
3268
			} elseif (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $token, $matches)) {
3269
//				echo 'Token is a function<br />';
3270
				$functionName = $matches[1];
3271
				$argCount = $stack->pop();
3272
				$argCount = $argCount['value'];
3273
				if ($functionName != 'MKMATRIX') {
3274
					$this->_writeDebug('Evaluating Function '.self::_localeFunc($functionName).'() with '.(($argCount == 0) ? 'no' : $argCount).' argument'.(($argCount == 1) ? '' : 's'));
3275
				}
3276
				if ((isset(self::$_PHPExcelFunctions[$functionName])) || (isset(self::$_controlFunctions[$functionName]))) {	// function
3277
					if (isset(self::$_PHPExcelFunctions[$functionName])) {
3278
						$functionCall = self::$_PHPExcelFunctions[$functionName]['functionCall'];
3279
						$passByReference = isset(self::$_PHPExcelFunctions[$functionName]['passByReference']);
3280
						$passCellReference = isset(self::$_PHPExcelFunctions[$functionName]['passCellReference']);
3281
					} elseif (isset(self::$_controlFunctions[$functionName])) {
3282
						$functionCall = self::$_controlFunctions[$functionName]['functionCall'];
3283
						$passByReference = isset(self::$_controlFunctions[$functionName]['passByReference']);
3284
						$passCellReference = isset(self::$_controlFunctions[$functionName]['passCellReference']);
3285
					}
3286
					// get the arguments for this function
3287
//					echo 'Function '.$functionName.' expects '.$argCount.' arguments<br />';
3288
					$args = $argArrayVals = array();
3289
					for ($i = 0; $i < $argCount; ++$i) {
3290
						$arg = $stack->pop();
3291
						$a = $argCount - $i - 1;
3292
						if (($passByReference) &&
0 ignored issues
show
Bug introduced by
The variable $passByReference 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...
3293
							(isset(self::$_PHPExcelFunctions[$functionName]['passByReference'][$a])) &&
3294
							(self::$_PHPExcelFunctions[$functionName]['passByReference'][$a])) {
3295
							if ($arg['reference'] === NULL) {
3296
								$args[] = $cellID;
3297
								if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($cellID); }
3298
							} else {
3299
								$args[] = $arg['reference'];
3300
								if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($arg['reference']); }
3301
							}
3302
						} else {
3303
							$args[] = self::_unwrapResult($arg['value']);
3304
							if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($arg['value']); }
3305
						}
3306
					}
3307
					//	Reverse the order of the arguments
3308
					krsort($args);
3309
					if (($passByReference) && ($argCount == 0)) {
3310
						$args[] = $cellID;
3311
						$argArrayVals[] = $this->_showValue($cellID);
3312
					}
3313
//					echo 'Arguments are: ';
3314
//					print_r($args);
3315
//					echo '<br />';
3316
					if ($functionName != 'MKMATRIX') {
3317
						if ($this->writeDebugLog) {
3318
							krsort($argArrayVals);
3319
							$this->_writeDebug('Evaluating '. self::_localeFunc($functionName).'( '.implode(self::$_localeArgumentSeparator.' ',PHPExcel_Calculation_Functions::flattenArray($argArrayVals)).' )');
3320
						}
3321
					}
3322
					//	Process each argument in turn, building the return value as an array
3323
//					if (($argCount == 1) && (is_array($args[1])) && ($functionName != 'MKMATRIX')) {
3324
//						$operand1 = $args[1];
3325
//						$this->_writeDebug('Argument is a matrix: '.$this->_showValue($operand1));
3326
//						$result = array();
3327
//						$row = 0;
3328
//						foreach($operand1 as $args) {
3329
//							if (is_array($args)) {
3330
//								foreach($args as $arg) {
3331
//									$this->_writeDebug('Evaluating '.self::_localeFunc($functionName).'( '.$this->_showValue($arg).' )');
3332
//									$r = call_user_func_array($functionCall,$arg);
3333
//									$this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($r));
3334
//									$result[$row][] = $r;
3335
//								}
3336
//								++$row;
3337
//							} else {
3338
//								$this->_writeDebug('Evaluating '.self::_localeFunc($functionName).'( '.$this->_showValue($args).' )');
3339
//								$r = call_user_func_array($functionCall,$args);
3340
//								$this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($r));
3341
//								$result[] = $r;
3342
//							}
3343
//						}
3344
//					} else {
3345
					//	Process the argument with the appropriate function call
3346
						if ($passCellReference) {
0 ignored issues
show
Bug introduced by
The variable $passCellReference 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...
3347
							$args[] = $pCell;
3348
						}
3349
						if (strpos($functionCall,'::') !== false) {
3350
							$result = call_user_func_array(explode('::',$functionCall),$args);
0 ignored issues
show
Bug introduced by
The variable $functionCall 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...
3351
						} else {
3352
							foreach($args as &$arg) {
3353
								$arg = PHPExcel_Calculation_Functions::flattenSingleValue($arg);
3354
							}
3355
							unset($arg);
3356
							$result = call_user_func_array($functionCall,$args);
3357
						}
3358
//					}
3359
					if ($functionName != 'MKMATRIX') {
3360
						$this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($result));
3361
					}
3362
					$stack->push('Value',self::_wrapResult($result));
3363
				}
3364
3365
			} else {
3366
				// if the token is a number, boolean, string or an Excel error, push it onto the stack
3367
				if (isset(self::$_ExcelConstants[strtoupper($token)])) {
3368
					$excelConstant = strtoupper($token);
3369
//					echo 'Token is a PHPExcel constant: '.$excelConstant.'<br />';
3370
					$stack->push('Constant Value',self::$_ExcelConstants[$excelConstant]);
3371
					$this->_writeDebug('Evaluating Constant '.$excelConstant.' as '.$this->_showTypeDetails(self::$_ExcelConstants[$excelConstant]));
3372
				} elseif ((is_numeric($token)) || ($token === NULL) || (is_bool($token)) || ($token == '') || ($token{0} == '"') || ($token{0} == '#')) {
3373
//					echo 'Token is a number, boolean, string, null or an Excel error<br />';
3374
					$stack->push('Value',$token);
3375
				// if the token is a named range, push the named range name onto the stack
3376
				} elseif (preg_match('/^'.self::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $token, $matches)) {
3377
//					echo 'Token is a named range<br />';
3378
					$namedRange = $matches[6];
3379
//					echo 'Named Range is '.$namedRange.'<br />';
3380
					$this->_writeDebug('Evaluating Named Range '.$namedRange);
3381
					$cellValue = $this->extractNamedRange($namedRange, ((null !== $pCell) ? $pCellParent : null), false);
3382
					$pCell->attach($pCellParent);
3383
					$this->_writeDebug('Evaluation Result for named range '.$namedRange.' is '.$this->_showTypeDetails($cellValue));
3384
					$stack->push('Named Range',$cellValue,$namedRange);
3385
				} else {
3386
					return $this->_raiseFormulaError("undefined variable '$token'");
3387
				}
3388
			}
3389
		}
3390
		// when we're out of tokens, the stack should have a single element, the final result
3391
		if ($stack->count() != 1) return $this->_raiseFormulaError("internal error");
3392
		$output = $stack->pop();
3393
		$output = $output['value'];
3394
3395
//		if ((is_array($output)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) {
3396
//			return array_shift(PHPExcel_Calculation_Functions::flattenArray($output));
3397
//		}
3398
		return $output;
3399
	}	//	function _processTokenStack()
3400
3401
3402
	private function _validateBinaryOperand($cellID,&$operand,&$stack) {
0 ignored issues
show
Unused Code introduced by
The parameter $cellID is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
3403
		//	Numbers, matrices and booleans can pass straight through, as they're already valid
3404
		if (is_string($operand)) {
3405
			//	We only need special validations for the operand if it is a string
3406
			//	Start by stripping off the quotation marks we use to identify true excel string values internally
3407
			if ($operand > '' && $operand{0} == '"') { $operand = self::_unwrapResult($operand); }
3408
			//	If the string is a numeric value, we treat it as a numeric, so no further testing
3409
			if (!is_numeric($operand)) {
3410
				//	If not a numeric, test to see if the value is an Excel error, and so can't be used in normal binary operations
3411
				if ($operand > '' && $operand{0} == '#') {
3412
					$stack->push('Value', $operand);
3413
					$this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($operand));
3414
					return false;
3415
				} elseif (!PHPExcel_Shared_String::convertToNumberIfFraction($operand)) {
3416
					//	If not a numeric or a fraction, then it's a text string, and so can't be used in mathematical binary operations
3417
					$stack->push('Value', '#VALUE!');
3418
					$this->_writeDebug('Evaluation Result is a '.$this->_showTypeDetails('#VALUE!'));
3419
					return false;
3420
				}
3421
			}
3422
		}
3423
3424
		//	return a true if the value of the operand is one that we can use in normal binary operations
3425
		return true;
3426
	}	//	function _validateBinaryOperand()
3427
3428
3429
	private function _executeBinaryComparisonOperation($cellID,$operand1,$operand2,$operation,&$stack,$recursingArrays=false) {
3430
		//	If we're dealing with matrix operations, we want a matrix result
3431
		if ((is_array($operand1)) || (is_array($operand2))) {
3432
			$result = array();
3433
			if ((is_array($operand1)) && (!is_array($operand2))) {
3434 View Code Duplication
				foreach($operand1 as $x => $operandData) {
3435
					$this->_writeDebug('Evaluating Comparison '.$this->_showValue($operandData).' '.$operation.' '.$this->_showValue($operand2));
3436
					$this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2,$operation,$stack);
3437
					$r = $stack->pop();
3438
					$result[$x] = $r['value'];
3439
				}
3440
			} elseif ((!is_array($operand1)) && (is_array($operand2))) {
3441 View Code Duplication
				foreach($operand2 as $x => $operandData) {
3442
					$this->_writeDebug('Evaluating Comparison '.$this->_showValue($operand1).' '.$operation.' '.$this->_showValue($operandData));
3443
					$this->_executeBinaryComparisonOperation($cellID,$operand1,$operandData,$operation,$stack);
3444
					$r = $stack->pop();
3445
					$result[$x] = $r['value'];
3446
				}
3447
			} else {
3448
				if (!$recursingArrays) { self::_checkMatrixOperands($operand1,$operand2,2); }
3449
				foreach($operand1 as $x => $operandData) {
3450
					$this->_writeDebug('Evaluating Comparison '.$this->_showValue($operandData).' '.$operation.' '.$this->_showValue($operand2[$x]));
3451
					$this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2[$x],$operation,$stack,true);
3452
					$r = $stack->pop();
3453
					$result[$x] = $r['value'];
3454
				}
3455
			}
3456
			//	Log the result details
3457
			$this->_writeDebug('Comparison Evaluation Result is '.$this->_showTypeDetails($result));
3458
			//	And push the result onto the stack
3459
			$stack->push('Array',$result);
3460
			return true;
3461
		}
3462
3463
		//	Simple validate the two operands if they are string values
3464
		if (is_string($operand1) && $operand1 > '' && $operand1{0} == '"') { $operand1 = self::_unwrapResult($operand1); }
3465
		if (is_string($operand2) && $operand2 > '' && $operand2{0} == '"') { $operand2 = self::_unwrapResult($operand2); }
3466
3467
		//	execute the necessary operation
3468
		switch ($operation) {
3469
			//	Greater than
3470
			case '>':
3471
				$result = ($operand1 > $operand2);
3472
				break;
3473
			//	Less than
3474
			case '<':
3475
				$result = ($operand1 < $operand2);
3476
				break;
3477
			//	Equality
3478
			case '=':
3479
				$result = ($operand1 == $operand2);
3480
				break;
3481
			//	Greater than or equal
3482
			case '>=':
3483
				$result = ($operand1 >= $operand2);
3484
				break;
3485
			//	Less than or equal
3486
			case '<=':
3487
				$result = ($operand1 <= $operand2);
3488
				break;
3489
			//	Inequality
3490
			case '<>':
3491
				$result = ($operand1 != $operand2);
3492
				break;
3493
		}
3494
3495
		//	Log the result details
3496
		$this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result));
0 ignored issues
show
Bug introduced by
The variable $result 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...
3497
		//	And push the result onto the stack
3498
		$stack->push('Value',$result);
3499
		return true;
3500
	}	//	function _executeBinaryComparisonOperation()
3501
3502
3503
	private function _executeNumericBinaryOperation($cellID,$operand1,$operand2,$operation,$matrixFunction,&$stack) {
3504
		//	Validate the two operands
3505
		if (!$this->_validateBinaryOperand($cellID,$operand1,$stack)) return false;
3506
		if (!$this->_validateBinaryOperand($cellID,$operand2,$stack)) return false;
3507
3508
		$executeMatrixOperation = false;
3509
		//	If either of the operands is a matrix, we need to treat them both as matrices
3510
		//		(converting the other operand to a matrix if need be); then perform the required
3511
		//		matrix operation
3512
		if ((is_array($operand1)) || (is_array($operand2))) {
3513
			//	Ensure that both operands are arrays/matrices
3514
			$executeMatrixOperation = true;
3515
			$mSize = array();
3516
			list($mSize[],$mSize[],$mSize[],$mSize[]) = self::_checkMatrixOperands($operand1,$operand2,2);
3517
3518
			//	But if they're both single cell matrices, then we can treat them as simple values
3519
			if (array_sum($mSize) == 4) {
3520
				$executeMatrixOperation = false;
3521
				$operand1 = $operand1[0][0];
3522
				$operand2 = $operand2[0][0];
3523
			}
3524
		}
3525
3526
		if ($executeMatrixOperation) {
3527
			try {
3528
				//	Convert operand 1 from a PHP array to a matrix
3529
				$matrix = new PHPExcel_Shared_JAMA_Matrix($operand1);
3530
				//	Perform the required operation against the operand 1 matrix, passing in operand 2
3531
				$matrixResult = $matrix->$matrixFunction($operand2);
3532
				$result = $matrixResult->getArray();
3533
			} catch (Exception $ex) {
3534
				$this->_writeDebug('JAMA Matrix Exception: '.$ex->getMessage());
3535
				$result = '#VALUE!';
3536
			}
3537
		} else {
3538
			if ((PHPExcel_Calculation_Functions::getCompatibilityMode() != PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) &&
3539
				((is_string($operand1) && !is_numeric($operand1)) || (is_string($operand2) && !is_numeric($operand2)))) {
3540
				$result = PHPExcel_Calculation_Functions::VALUE();
3541
			} else {
3542
				//	If we're dealing with non-matrix operations, execute the necessary operation
3543
				switch ($operation) {
3544
					//	Addition
3545
					case '+':
3546
						$result = $operand1+$operand2;
3547
						break;
3548
					//	Subtraction
3549
					case '-':
3550
						$result = $operand1-$operand2;
3551
						break;
3552
					//	Multiplication
3553
					case '*':
3554
						$result = $operand1*$operand2;
3555
						break;
3556
					//	Division
3557
					case '/':
3558
						if ($operand2 == 0) {
3559
							//	Trap for Divide by Zero error
3560
							$stack->push('Value','#DIV/0!');
3561
							$this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails('#DIV/0!'));
3562
							return false;
3563
						} else {
3564
							$result = $operand1/$operand2;
3565
						}
3566
						break;
3567
					//	Power
3568
					case '^':
3569
						$result = pow($operand1,$operand2);
3570
						break;
3571
				}
3572
			}
3573
		}
3574
3575
		//	Log the result details
3576
		$this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result));
0 ignored issues
show
Bug introduced by
The variable $result 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...
3577
		//	And push the result onto the stack
3578
		$stack->push('Value',$result);
3579
		return true;
3580
	}	//	function _executeNumericBinaryOperation()
3581
3582
3583
	private function _writeDebug($message) {
3584
		//	Only write the debug log if logging is enabled
3585
		if ($this->writeDebugLog) {
3586
			if ($this->echoDebugLog) {
3587
				echo implode(' -> ',$this->debugLogStack).' -> '.$message,'<br />';
3588
			}
3589
			$this->debugLog[] = implode(' -> ',$this->debugLogStack).' -> '.$message;
3590
		}
3591
	}	//	function _writeDebug()
3592
3593
3594
	// trigger an error, but nicely, if need be
3595
	protected function _raiseFormulaError($errorMessage) {
3596
		$this->formulaError = $errorMessage;
3597
		$this->debugLogStack = array();
3598
		if (!$this->suppressFormulaErrors) throw new Exception($errorMessage);
3599
		trigger_error($errorMessage, E_USER_ERROR);
3600
	}	//	function _raiseFormulaError()
3601
3602
3603
	/**
3604
	 * Extract range values
3605
	 *
3606
	 * @param	string				&$pRange		String based range representation
3607
	 * @param	PHPExcel_Worksheet	$pSheet		Worksheet
3608
	 * @return  mixed				Array of values in range if range contains more than one element. Otherwise, a single value is returned.
3609
	 * @throws	Exception
3610
	 */
3611
	public function extractCellRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = null, $resetLog=true) {
3612
		// Return value
3613
		$returnValue = array ();
3614
3615
//		echo 'extractCellRange('.$pRange.')<br />';
3616
		if ($pSheet !== NULL) {
3617
//			echo 'Passed sheet name is '.$pSheet->getTitle().'<br />';
3618
//			echo 'Range reference is '.$pRange.'<br />';
3619 View Code Duplication
			if (strpos ($pRange, '!') !== false) {
3620
//				echo '$pRange reference includes sheet reference<br />';
3621
				$worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pRange, true);
3622
				$pSheet = $pSheet->getParent()->getSheetByName($worksheetReference[0]);
3623
//				echo 'New sheet name is '.$pSheet->getTitle().'<br />';
3624
				$pRange = $worksheetReference[1];
3625
//				echo 'Adjusted Range reference is '.$pRange.'<br />';
3626
			}
3627
3628
			// Extract range
3629
			$aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange);
3630
			$pRange = $pSheet->getTitle().'!'.$pRange;
0 ignored issues
show
Bug introduced by
It seems like $pSheet is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
3631
			if (!isset($aReferences[1])) {
3632
				//	Single cell in range
3633
				list($currentCol,$currentRow) = sscanf($aReferences[0],'%[A-Z]%d');
3634 View Code Duplication
				if ($pSheet->cellExists($aReferences[0])) {
3635
					$returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
3636
				} else {
3637
					$returnValue[$currentRow][$currentCol] = null;
3638
				}
3639
			} else {
3640
				// Extract cell data for all cells in the range
3641
				foreach ($aReferences as $reference) {
3642
					// Extract range
3643
					list($currentCol,$currentRow) = sscanf($reference,'%[A-Z]%d');
3644
3645 View Code Duplication
					if ($pSheet->cellExists($reference)) {
3646
						$returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
3647
					} else {
3648
						$returnValue[$currentRow][$currentCol] = null;
3649
					}
3650
				}
3651
			}
3652
		}
3653
3654
		// Return
3655
		return $returnValue;
3656
	}	//	function extractCellRange()
3657
3658
3659
	/**
3660
	 * Extract range values
3661
	 *
3662
	 * @param	string				&$pRange	String based range representation
3663
	 * @param	PHPExcel_Worksheet	$pSheet		Worksheet
3664
	 * @return  mixed				Array of values in range if range contains more than one element. Otherwise, a single value is returned.
3665
	 * @throws	Exception
3666
	 */
3667
	public function extractNamedRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = null, $resetLog=true) {
3668
		// Return value
3669
		$returnValue = array ();
3670
3671
//		echo 'extractNamedRange('.$pRange.')<br />';
3672
		if ($pSheet !== NULL) {
3673
//			echo 'Current sheet name is '.$pSheet->getTitle().'<br />';
3674
//			echo 'Range reference is '.$pRange.'<br />';
3675 View Code Duplication
			if (strpos ($pRange, '!') !== false) {
3676
//				echo '$pRange reference includes sheet reference<br />';
3677
				$worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pRange, true);
3678
				$pSheet = $pSheet->getParent()->getSheetByName($worksheetReference[0]);
3679
//				echo 'New sheet name is '.$pSheet->getTitle().'<br />';
3680
				$pRange = $worksheetReference[1];
3681
//				echo 'Adjusted Range reference is '.$pRange.'<br />';
3682
			}
3683
3684
			// Named range?
3685
			$namedRange = PHPExcel_NamedRange::resolveRange($pRange, $pSheet);
0 ignored issues
show
Bug introduced by
It seems like $pSheet can be null; however, resolveRange() 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...
3686
			if ($namedRange !== NULL) {
3687
				$pSheet = $namedRange->getWorksheet();
3688
//				echo 'Named Range '.$pRange.' (';
3689
				$pRange = $namedRange->getRange();
3690
				$splitRange = PHPExcel_Cell::splitRange($pRange);
3691
				//	Convert row and column references
3692
				if (ctype_alpha($splitRange[0][0])) {
3693
					$pRange = $splitRange[0][0] . '1:' . $splitRange[0][1] . $namedRange->getWorksheet()->getHighestRow();
3694
				} elseif(ctype_digit($splitRange[0][0])) {
3695
					$pRange = 'A' . $splitRange[0][0] . ':' . $namedRange->getWorksheet()->getHighestColumn() . $splitRange[0][1];
3696
				}
3697
//				echo $pRange.') is in sheet '.$namedRange->getWorksheet()->getTitle().'<br />';
3698
3699
//				if ($pSheet->getTitle() != $namedRange->getWorksheet()->getTitle()) {
3700
//					if (!$namedRange->getLocalOnly()) {
3701
//						$pSheet = $namedRange->getWorksheet();
3702
//					} else {
3703
//						return $returnValue;
3704
//					}
3705
//				}
3706
			} else {
3707
				return PHPExcel_Calculation_Functions::REF();
3708
			}
3709
3710
			// Extract range
3711
			$aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange);
3712
//			var_dump($aReferences);
3713
			if (!isset($aReferences[1])) {
3714
				//	Single cell (or single column or row) in range
3715
				list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($aReferences[0]);
3716 View Code Duplication
				if ($pSheet->cellExists($aReferences[0])) {
3717
					$returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
3718
				} else {
3719
					$returnValue[$currentRow][$currentCol] = null;
3720
				}
3721
			} else {
3722
				// Extract cell data for all cells in the range
3723
				foreach ($aReferences as $reference) {
3724
					// Extract range
3725
					list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($reference);
3726
//					echo 'NAMED RANGE: $currentCol='.$currentCol.' $currentRow='.$currentRow.'<br />';
3727 View Code Duplication
					if ($pSheet->cellExists($reference)) {
3728
						$returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
3729
					} else {
3730
						$returnValue[$currentRow][$currentCol] = null;
3731
					}
3732
				}
3733
			}
3734
//				print_r($returnValue);
3735
//			echo '<br />';
3736
		}
3737
3738
		// Return
3739
		return $returnValue;
3740
	}	//	function extractNamedRange()
3741
3742
3743
	/**
3744
	 * Is a specific function implemented?
3745
	 *
3746
	 * @param	string	$pFunction	Function Name
3747
	 * @return	boolean
3748
	 */
3749
	public function isImplemented($pFunction = '') {
3750
		$pFunction = strtoupper ($pFunction);
3751
		if (isset(self::$_PHPExcelFunctions[$pFunction])) {
3752
			return (self::$_PHPExcelFunctions[$pFunction]['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY');
3753
		} else {
3754
			return false;
3755
		}
3756
	}	//	function isImplemented()
3757
3758
3759
	/**
3760
	 * Get a list of all implemented functions as an array of function objects
3761
	 *
3762
	 * @return	array of PHPExcel_Calculation_Function
3763
	 */
3764
	public function listFunctions() {
3765
		// Return value
3766
		$returnValue = array();
3767
		// Loop functions
3768
		foreach(self::$_PHPExcelFunctions as $functionName => $function) {
3769
			if ($function['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY') {
3770
				$returnValue[$functionName] = new PHPExcel_Calculation_Function($function['category'],
3771
																				$functionName,
3772
																				$function['functionCall']
3773
																			   );
3774
			}
3775
		}
3776
3777
		// Return
3778
		return $returnValue;
3779
	}	//	function listFunctions()
3780
3781
3782
	/**
3783
	 * Get a list of all Excel function names
3784
	 *
3785
	 * @return	array
3786
	 */
3787
	public function listAllFunctionNames() {
3788
		return array_keys(self::$_PHPExcelFunctions);
3789
	}	//	function listAllFunctionNames()
3790
3791
	/**
3792
	 * Get a list of implemented Excel function names
3793
	 *
3794
	 * @return	array
3795
	 */
3796
	public function listFunctionNames() {
3797
		// Return value
3798
		$returnValue = array();
3799
		// Loop functions
3800
		foreach(self::$_PHPExcelFunctions as $functionName => $function) {
3801
			if ($function['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY') {
3802
				$returnValue[] = $functionName;
3803
			}
3804
		}
3805
3806
		// Return
3807
		return $returnValue;
3808
	}	//	function listFunctionNames()
3809
3810
}	//	class PHPExcel_Calculation
3811
3812
3813
3814
3815
// for internal use
3816
class PHPExcel_Token_Stack {
3817
3818
	private $_stack = array();
3819
	private $_count = 0;
3820
3821
3822
	public function count() {
3823
		return $this->_count;
3824
	}	//	function count()
3825
3826
3827
	public function push($type,$value,$reference=null) {
3828
		$this->_stack[$this->_count++] = array('type'		=> $type,
3829
											   'value'		=> $value,
3830
											   'reference'	=> $reference
3831
											  );
3832
		if ($type == 'Function') {
3833
			$localeFunction = PHPExcel_Calculation::_localeFunc($value);
3834
			if ($localeFunction != $value) {
3835
				$this->_stack[($this->_count - 1)]['localeValue'] = $localeFunction;
3836
			}
3837
		}
3838
	}	//	function push()
3839
3840
3841
	public function pop() {
3842
		if ($this->_count > 0) {
3843
			return $this->_stack[--$this->_count];
3844
		}
3845
		return null;
3846
	}	//	function pop()
3847
3848
3849
	public function last($n=1) {
3850
		if ($this->_count-$n < 0) {
3851
			return null;
3852
		}
3853
		return $this->_stack[$this->_count-$n];
3854
	}	//	function last()
3855
3856
3857
	function __construct() {
3858
	}
3859
3860
}	//	class PHPExcel_Token_Stack
3861