@@ -37,6 +37,10 @@ class Calculation
37
37
const RETURN_ARRAY_AS_VALUE = 'value ' ;
38
38
const RETURN_ARRAY_AS_ARRAY = 'array ' ;
39
39
40
+ const FORMULA_OPEN_FUNCTION_BRACE = '{ ' ;
41
+ const FORMULA_CLOSE_FUNCTION_BRACE = '} ' ;
42
+ const FORMULA_STRING_QUOTE = '" ' ;
43
+
40
44
private static $ returnArrayAsType = self ::RETURN_ARRAY_AS_VALUE ;
41
45
42
46
/**
@@ -2593,11 +2597,11 @@ public static function translateSeparator($fromSeparator, $toSeparator, $formula
2593
2597
for ($ i = 0 ; $ i < $ strlen ; ++$ i ) {
2594
2598
$ chr = mb_substr ($ formula , $ i , 1 );
2595
2599
switch ($ chr ) {
2596
- case ' { ' :
2600
+ case self :: FORMULA_OPEN_FUNCTION_BRACE :
2597
2601
$ inBraces = true ;
2598
2602
2599
2603
break ;
2600
- case ' } ' :
2604
+ case self :: FORMULA_CLOSE_FUNCTION_BRACE :
2601
2605
$ inBraces = false ;
2602
2606
2603
2607
break ;
@@ -2626,10 +2630,10 @@ private static function translateFormula(array $from, array $to, $formula, $from
2626
2630
if (self ::$ localeLanguage !== 'en_us ' ) {
2627
2631
$ inBraces = false ;
2628
2632
// If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
2629
- if (strpos ($ formula , ' " ' ) !== false ) {
2633
+ if (strpos ($ formula , self :: FORMULA_STRING_QUOTE ) !== false ) {
2630
2634
// So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
2631
2635
// the formula
2632
- $ temp = explode (' " ' , $ formula );
2636
+ $ temp = explode (self :: FORMULA_STRING_QUOTE , $ formula );
2633
2637
$ i = false ;
2634
2638
foreach ($ temp as &$ value ) {
2635
2639
// Only count/replace in alternating array entries
@@ -2640,7 +2644,7 @@ private static function translateFormula(array $from, array $to, $formula, $from
2640
2644
}
2641
2645
unset($ value );
2642
2646
// Then rebuild the formula string
2643
- $ formula = implode (' " ' , $ temp );
2647
+ $ formula = implode (self :: FORMULA_STRING_QUOTE , $ temp );
2644
2648
} else {
2645
2649
// If there's no quoted strings, then we do a simple count/replace
2646
2650
$ formula = preg_replace ($ from , $ to , $ formula );
@@ -2741,7 +2745,7 @@ public static function wrapResult($value)
2741
2745
return $ value ;
2742
2746
}
2743
2747
// Return strings wrapped in quotes
2744
- return ' " ' . $ value . ' " ' ;
2748
+ return self :: FORMULA_STRING_QUOTE . $ value . self :: FORMULA_STRING_QUOTE ;
2745
2749
// Convert numeric errors to NaN error
2746
2750
} elseif ((is_float ($ value )) && ((is_nan ($ value )) || (is_infinite ($ value )))) {
2747
2751
return Functions::NAN ();
@@ -2760,7 +2764,7 @@ public static function wrapResult($value)
2760
2764
public static function unwrapResult ($ value )
2761
2765
{
2762
2766
if (is_string ($ value )) {
2763
- if ((isset ($ value [0 ])) && ($ value [0 ] == ' " ' ) && (substr ($ value , -1 ) == ' " ' )) {
2767
+ if ((isset ($ value [0 ])) && ($ value [0 ] == self :: FORMULA_STRING_QUOTE ) && (substr ($ value , -1 ) == self :: FORMULA_STRING_QUOTE )) {
2764
2768
return substr ($ value , 1 , -1 );
2765
2769
}
2766
2770
// Convert numeric errors to NAN error
@@ -3227,8 +3231,8 @@ private function showValue($value)
3227
3231
}
3228
3232
3229
3233
return '{ ' . implode ($ rpad , $ returnMatrix ) . ' } ' ;
3230
- } elseif (is_string ($ value ) && (trim ($ value , ' " ' ) == $ value )) {
3231
- return ' " ' . $ value . ' " ' ;
3234
+ } elseif (is_string ($ value ) && (trim ($ value , self :: FORMULA_STRING_QUOTE ) == $ value )) {
3235
+ return self :: FORMULA_STRING_QUOTE . $ value . self :: FORMULA_STRING_QUOTE ;
3232
3236
} elseif (is_bool ($ value )) {
3233
3237
return ($ value ) ? self ::$ localeBoolean ['TRUE ' ] : self ::$ localeBoolean ['FALSE ' ];
3234
3238
}
@@ -3282,34 +3286,34 @@ private function showTypeDetails($value)
3282
3286
*/
3283
3287
private function convertMatrixReferences ($ formula )
3284
3288
{
3285
- static $ matrixReplaceFrom = [' { ' , '; ' , ' } ' ];
3289
+ static $ matrixReplaceFrom = [self :: FORMULA_OPEN_FUNCTION_BRACE , '; ' , self :: FORMULA_CLOSE_FUNCTION_BRACE ];
3286
3290
static $ matrixReplaceTo = ['MKMATRIX(MKMATRIX( ' , '),MKMATRIX( ' , ')) ' ];
3287
3291
3288
3292
// Convert any Excel matrix references to the MKMATRIX() function
3289
- if (strpos ($ formula , ' { ' ) !== false ) {
3293
+ if (strpos ($ formula , self :: FORMULA_OPEN_FUNCTION_BRACE ) !== false ) {
3290
3294
// If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
3291
- if (strpos ($ formula , ' " ' ) !== false ) {
3295
+ if (strpos ($ formula , self :: FORMULA_STRING_QUOTE ) !== false ) {
3292
3296
// So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
3293
3297
// the formula
3294
- $ temp = explode (' " ' , $ formula );
3298
+ $ temp = explode (self :: FORMULA_STRING_QUOTE , $ formula );
3295
3299
// Open and Closed counts used for trapping mismatched braces in the formula
3296
3300
$ openCount = $ closeCount = 0 ;
3297
3301
$ i = false ;
3298
3302
foreach ($ temp as &$ value ) {
3299
3303
// Only count/replace in alternating array entries
3300
3304
if ($ i = !$ i ) {
3301
- $ openCount += substr_count ($ value , ' { ' );
3302
- $ closeCount += substr_count ($ value , ' } ' );
3305
+ $ openCount += substr_count ($ value , self :: FORMULA_OPEN_FUNCTION_BRACE );
3306
+ $ closeCount += substr_count ($ value , self :: FORMULA_CLOSE_FUNCTION_BRACE );
3303
3307
$ value = str_replace ($ matrixReplaceFrom , $ matrixReplaceTo , $ value );
3304
3308
}
3305
3309
}
3306
3310
unset($ value );
3307
3311
// Then rebuild the formula string
3308
- $ formula = implode (' " ' , $ temp );
3312
+ $ formula = implode (self :: FORMULA_STRING_QUOTE , $ temp );
3309
3313
} else {
3310
3314
// If there's no quoted strings, then we do a simple count/replace
3311
- $ openCount = substr_count ($ formula , ' { ' );
3312
- $ closeCount = substr_count ($ formula , ' } ' );
3315
+ $ openCount = substr_count ($ formula , self :: FORMULA_OPEN_FUNCTION_BRACE );
3316
+ $ closeCount = substr_count ($ formula , self :: FORMULA_CLOSE_FUNCTION_BRACE );
3313
3317
$ formula = str_replace ($ matrixReplaceFrom , $ matrixReplaceTo , $ formula );
3314
3318
}
3315
3319
// Trap for mismatched braces and trigger an appropriate error
@@ -3715,9 +3719,9 @@ private function _parseFormula($formula, ?Cell $pCell = null)
3715
3719
}
3716
3720
3717
3721
$ localeConstant = false ;
3718
- if ($ opCharacter == ' " ' ) {
3722
+ if ($ opCharacter == self :: FORMULA_STRING_QUOTE ) {
3719
3723
// UnEscape any quotes within the string
3720
- $ val = self ::wrapResult (str_replace ('"" ' , ' " ' , self ::unwrapResult ($ val )));
3724
+ $ val = self ::wrapResult (str_replace ('"" ' , self :: FORMULA_STRING_QUOTE , self ::unwrapResult ($ val )));
3721
3725
} elseif (is_numeric ($ val )) {
3722
3726
if ((strpos ($ val , '. ' ) !== false ) || (stripos ($ val , 'e ' ) !== false ) || ($ val > PHP_INT_MAX ) || ($ val < -PHP_INT_MAX )) {
3723
3727
$ val = (float ) $ val ;
@@ -4058,7 +4062,7 @@ private function processTokenStack($tokens, $cellID = null, ?Cell $pCell = null)
4058
4062
$ result = '#VALUE! ' ;
4059
4063
}
4060
4064
} else {
4061
- $ result = ' " ' . str_replace ('"" ' , ' " ' , self ::unwrapResult ($ operand1 ) . self ::unwrapResult ($ operand2 )) . ' " ' ;
4065
+ $ result = self :: FORMULA_STRING_QUOTE . str_replace ('"" ' , self :: FORMULA_STRING_QUOTE , self ::unwrapResult ($ operand1 ) . self ::unwrapResult ($ operand2 )) . self :: FORMULA_STRING_QUOTE ;
4062
4066
}
4063
4067
$ this ->debugLog ->writeDebugLog ('Evaluation Result is ' , $ this ->showTypeDetails ($ result ));
4064
4068
$ stack ->push ('Value ' , $ result );
@@ -4078,9 +4082,15 @@ private function processTokenStack($tokens, $cellID = null, ?Cell $pCell = null)
4078
4082
$ cellIntersect [$ row ] = array_intersect_key ($ operand1 [$ row ], $ operand2 [$ row ]);
4079
4083
}
4080
4084
}
4081
- $ cellRef = Coordinate::stringFromColumnIndex (min ($ oCol ) + 1 ) . min ($ oRow ) . ': ' . Coordinate::stringFromColumnIndex (max ($ oCol ) + 1 ) . max ($ oRow );
4082
- $ this ->debugLog ->writeDebugLog ('Evaluation Result is ' , $ this ->showTypeDetails ($ cellIntersect ));
4083
- $ stack ->push ('Value ' , $ cellIntersect , $ cellRef );
4085
+ if (count (Functions::flattenArray ($ cellIntersect )) === 0 ) {
4086
+ $ this ->debugLog ->writeDebugLog ('Evaluation Result is ' , $ this ->showTypeDetails ($ cellIntersect ));
4087
+ $ stack ->push ('Error ' , Functions::null (), null );
4088
+ } else {
4089
+ $ cellRef = Coordinate::stringFromColumnIndex (min ($ oCol ) + 1 ) . min ($ oRow ) . ': ' .
4090
+ Coordinate::stringFromColumnIndex (max ($ oCol ) + 1 ) . max ($ oRow );
4091
+ $ this ->debugLog ->writeDebugLog ('Evaluation Result is ' , $ this ->showTypeDetails ($ cellIntersect ));
4092
+ $ stack ->push ('Value ' , $ cellIntersect , $ cellRef );
4093
+ }
4084
4094
4085
4095
break ;
4086
4096
}
@@ -4284,7 +4294,7 @@ private function processTokenStack($tokens, $cellID = null, ?Cell $pCell = null)
4284
4294
$ branchStore [$ storeKey ] = self ::$ excelConstants [$ excelConstant ];
4285
4295
}
4286
4296
$ this ->debugLog ->writeDebugLog ('Evaluating Constant ' , $ excelConstant , ' as ' , $ this ->showTypeDetails (self ::$ excelConstants [$ excelConstant ]));
4287
- } elseif ((is_numeric ($ token )) || ($ token === null ) || (is_bool ($ token )) || ($ token == '' ) || ($ token [0 ] == ' " ' ) || ($ token [0 ] == '# ' )) {
4297
+ } elseif ((is_numeric ($ token )) || ($ token === null ) || (is_bool ($ token )) || ($ token == '' ) || ($ token [0 ] == self :: FORMULA_STRING_QUOTE ) || ($ token [0 ] == '# ' )) {
4288
4298
$ stack ->push ('Value ' , $ token );
4289
4299
if (isset ($ storeKey )) {
4290
4300
$ branchStore [$ storeKey ] = $ token ;
@@ -4329,7 +4339,7 @@ private function validateBinaryOperand(&$operand, &$stack)
4329
4339
if (is_string ($ operand )) {
4330
4340
// We only need special validations for the operand if it is a string
4331
4341
// Start by stripping off the quotation marks we use to identify true excel string values internally
4332
- if ($ operand > '' && $ operand [0 ] == ' " ' ) {
4342
+ if ($ operand > '' && $ operand [0 ] == self :: FORMULA_STRING_QUOTE ) {
4333
4343
$ operand = self ::unwrapResult ($ operand );
4334
4344
}
4335
4345
// If the string is a numeric value, we treat it as a numeric, so no further testing
@@ -4342,7 +4352,7 @@ private function validateBinaryOperand(&$operand, &$stack)
4342
4352
return false ;
4343
4353
} elseif (!Shared \StringHelper::convertToNumberIfFraction ($ operand )) {
4344
4354
// If not a numeric or a fraction, then it's a text string, and so can't be used in mathematical binary operations
4345
- $ stack ->push ('Value ' , '#VALUE! ' );
4355
+ $ stack ->push ('Error ' , '#VALUE! ' );
4346
4356
$ this ->debugLog ->writeDebugLog ('Evaluation Result is a ' , $ this ->showTypeDetails ('#VALUE! ' ));
4347
4357
4348
4358
return false ;
@@ -4402,10 +4412,10 @@ private function executeBinaryComparisonOperation($cellID, $operand1, $operand2,
4402
4412
}
4403
4413
4404
4414
// Simple validate the two operands if they are string values
4405
- if (is_string ($ operand1 ) && $ operand1 > '' && $ operand1 [0 ] == ' " ' ) {
4415
+ if (is_string ($ operand1 ) && $ operand1 > '' && $ operand1 [0 ] == self :: FORMULA_STRING_QUOTE ) {
4406
4416
$ operand1 = self ::unwrapResult ($ operand1 );
4407
4417
}
4408
- if (is_string ($ operand2 ) && $ operand2 > '' && $ operand2 [0 ] == ' " ' ) {
4418
+ if (is_string ($ operand2 ) && $ operand2 > '' && $ operand2 [0 ] == self :: FORMULA_STRING_QUOTE ) {
4409
4419
$ operand2 = self ::unwrapResult ($ operand2 );
4410
4420
}
4411
4421
@@ -4570,7 +4580,7 @@ private function executeNumericBinaryOperation($operand1, $operand2, $operation,
4570
4580
case '/ ' :
4571
4581
if ($ operand2 == 0 ) {
4572
4582
// Trap for Divide by Zero error
4573
- $ stack ->push ('Value ' , '#DIV/0! ' );
4583
+ $ stack ->push ('Error ' , '#DIV/0! ' );
4574
4584
$ this ->debugLog ->writeDebugLog ('Evaluation Result is ' , $ this ->showTypeDetails ('#DIV/0! ' ));
4575
4585
4576
4586
return false ;
0 commit comments