[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * PHPExcel 4 * 5 * Copyright (c) 2006 - 2014 PHPExcel 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 * 21 * @category PHPExcel 22 * @package PHPExcel_Calculation 23 * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel) 24 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL 25 * @version ##VERSION##, ##DATE## 26 */ 27 28 29 /** PHPExcel root directory */ 30 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 (Multiton) 57 * 58 * @category PHPExcel 59 * @package PHPExcel_Calculation 60 * @copyright Copyright (c) 2006 - 2014 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 * Instance of the workbook this Calculation Engine is using 101 * 102 * @access private 103 * @var PHPExcel 104 */ 105 private $_workbook; 106 107 /** 108 * List of instances of the calculation engine that we've instantiated for individual workbooks 109 * 110 * @access private 111 * @var PHPExcel_Calculation[] 112 */ 113 private static $_workbookSets; 114 115 /** 116 * Calculation cache 117 * 118 * @access private 119 * @var array 120 */ 121 private $_calculationCache = array (); 122 123 124 /** 125 * Calculation cache enabled 126 * 127 * @access private 128 * @var boolean 129 */ 130 private $_calculationCacheEnabled = TRUE; 131 132 133 /** 134 * List of operators that can be used within formulae 135 * The true/false value indicates whether it is a binary operator or a unary operator 136 * 137 * @access private 138 * @var array 139 */ 140 private static $_operators = array('+' => TRUE, '-' => TRUE, '*' => TRUE, '/' => TRUE, 141 '^' => TRUE, '&' => TRUE, '%' => FALSE, '~' => FALSE, 142 '>' => TRUE, '<' => TRUE, '=' => TRUE, '>=' => TRUE, 143 '<=' => TRUE, '<>' => TRUE, '|' => TRUE, ':' => TRUE 144 ); 145 146 147 /** 148 * List of binary operators (those that expect two operands) 149 * 150 * @access private 151 * @var array 152 */ 153 private static $_binaryOperators = array('+' => TRUE, '-' => TRUE, '*' => TRUE, '/' => TRUE, 154 '^' => TRUE, '&' => TRUE, '>' => TRUE, '<' => TRUE, 155 '=' => TRUE, '>=' => TRUE, '<=' => TRUE, '<>' => TRUE, 156 '|' => TRUE, ':' => TRUE 157 ); 158 159 /** 160 * The debug log generated by the calculation engine 161 * 162 * @access private 163 * @var PHPExcel_CalcEngine_Logger 164 * 165 */ 166 private $debugLog; 167 168 /** 169 * Flag to determine how formula errors should be handled 170 * If true, then a user error will be triggered 171 * If false, then an exception will be thrown 172 * 173 * @access public 174 * @var boolean 175 * 176 */ 177 public $suppressFormulaErrors = FALSE; 178 179 /** 180 * Error message for any error that was raised/thrown by the calculation engine 181 * 182 * @access public 183 * @var string 184 * 185 */ 186 public $formulaError = NULL; 187 188 /** 189 * An array of the nested cell references accessed by the calculation engine, used for the debug log 190 * 191 * @access private 192 * @var array of string 193 * 194 */ 195 private $_cyclicReferenceStack; 196 197 /** 198 * Current iteration counter for cyclic formulae 199 * If the value is 0 (or less) then cyclic formulae will throw an exception, 200 * otherwise they will iterate to the limit defined here before returning a result 201 * 202 * @var integer 203 * 204 */ 205 private $_cyclicFormulaCount = 0; 206 207 private $_cyclicFormulaCell = ''; 208 209 /** 210 * Number of iterations for cyclic formulae 211 * 212 * @var integer 213 * 214 */ 215 public $cyclicFormulaCount = 0; 216 217 /** 218 * Precision used for calculations 219 * 220 * @var integer 221 * 222 */ 223 private $_savedPrecision = 14; 224 225 226 /** 227 * The current locale setting 228 * 229 * @var string 230 * 231 */ 232 private static $_localeLanguage = 'en_us'; // US English (default locale) 233 234 /** 235 * List of available locale settings 236 * Note that this is read for the locale subdirectory only when requested 237 * 238 * @var string[] 239 * 240 */ 241 private static $_validLocaleLanguages = array( 'en' // English (default language) 242 ); 243 /** 244 * Locale-specific argument separator for function arguments 245 * 246 * @var string 247 * 248 */ 249 private static $_localeArgumentSeparator = ','; 250 private static $_localeFunctions = array(); 251 252 /** 253 * Locale-specific translations for Excel constants (True, False and Null) 254 * 255 * @var string[] 256 * 257 */ 258 public static $_localeBoolean = array( 'TRUE' => 'TRUE', 259 'FALSE' => 'FALSE', 260 'NULL' => 'NULL' 261 ); 262 263 264 /** 265 * Excel constant string translations to their PHP equivalents 266 * Constant conversion from text name/value to actual (datatyped) value 267 * 268 * @var string[] 269 * 270 */ 271 private static $_ExcelConstants = array('TRUE' => TRUE, 272 'FALSE' => FALSE, 273 'NULL' => NULL 274 ); 275 276 // PHPExcel functions 277 private static $_PHPExcelFunctions = array( // PHPExcel functions 278 'ABS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 279 'functionCall' => 'abs', 280 'argumentCount' => '1' 281 ), 282 'ACCRINT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 283 'functionCall' => 'PHPExcel_Calculation_Financial::ACCRINT', 284 'argumentCount' => '4-7' 285 ), 286 'ACCRINTM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 287 'functionCall' => 'PHPExcel_Calculation_Financial::ACCRINTM', 288 'argumentCount' => '3-5' 289 ), 290 'ACOS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 291 'functionCall' => 'acos', 292 'argumentCount' => '1' 293 ), 294 'ACOSH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 295 'functionCall' => 'acosh', 296 'argumentCount' => '1' 297 ), 298 'ADDRESS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 299 'functionCall' => 'PHPExcel_Calculation_LookupRef::CELL_ADDRESS', 300 'argumentCount' => '2-5' 301 ), 302 'AMORDEGRC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 303 'functionCall' => 'PHPExcel_Calculation_Financial::AMORDEGRC', 304 'argumentCount' => '6,7' 305 ), 306 'AMORLINC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 307 'functionCall' => 'PHPExcel_Calculation_Financial::AMORLINC', 308 'argumentCount' => '6,7' 309 ), 310 'AND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, 311 'functionCall' => 'PHPExcel_Calculation_Logical::LOGICAL_AND', 312 'argumentCount' => '1+' 313 ), 314 'AREAS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 315 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 316 'argumentCount' => '1' 317 ), 318 'ASC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 319 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 320 'argumentCount' => '1' 321 ), 322 'ASIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 323 'functionCall' => 'asin', 324 'argumentCount' => '1' 325 ), 326 'ASINH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 327 'functionCall' => 'asinh', 328 'argumentCount' => '1' 329 ), 330 'ATAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 331 'functionCall' => 'atan', 332 'argumentCount' => '1' 333 ), 334 'ATAN2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 335 'functionCall' => 'PHPExcel_Calculation_MathTrig::ATAN2', 336 'argumentCount' => '2' 337 ), 338 'ATANH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 339 'functionCall' => 'atanh', 340 'argumentCount' => '1' 341 ), 342 'AVEDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 343 'functionCall' => 'PHPExcel_Calculation_Statistical::AVEDEV', 344 'argumentCount' => '1+' 345 ), 346 'AVERAGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 347 'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGE', 348 'argumentCount' => '1+' 349 ), 350 'AVERAGEA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 351 'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGEA', 352 'argumentCount' => '1+' 353 ), 354 'AVERAGEIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 355 'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGEIF', 356 'argumentCount' => '2,3' 357 ), 358 'AVERAGEIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 359 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 360 'argumentCount' => '3+' 361 ), 362 'BAHTTEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 363 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 364 'argumentCount' => '1' 365 ), 366 'BESSELI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 367 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELI', 368 'argumentCount' => '2' 369 ), 370 'BESSELJ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 371 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELJ', 372 'argumentCount' => '2' 373 ), 374 'BESSELK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 375 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELK', 376 'argumentCount' => '2' 377 ), 378 'BESSELY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 379 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELY', 380 'argumentCount' => '2' 381 ), 382 'BETADIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 383 'functionCall' => 'PHPExcel_Calculation_Statistical::BETADIST', 384 'argumentCount' => '3-5' 385 ), 386 'BETAINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 387 'functionCall' => 'PHPExcel_Calculation_Statistical::BETAINV', 388 'argumentCount' => '3-5' 389 ), 390 'BIN2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 391 'functionCall' => 'PHPExcel_Calculation_Engineering::BINTODEC', 392 'argumentCount' => '1' 393 ), 394 'BIN2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 395 'functionCall' => 'PHPExcel_Calculation_Engineering::BINTOHEX', 396 'argumentCount' => '1,2' 397 ), 398 'BIN2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 399 'functionCall' => 'PHPExcel_Calculation_Engineering::BINTOOCT', 400 'argumentCount' => '1,2' 401 ), 402 'BINOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 403 'functionCall' => 'PHPExcel_Calculation_Statistical::BINOMDIST', 404 'argumentCount' => '4' 405 ), 406 'CEILING' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 407 'functionCall' => 'PHPExcel_Calculation_MathTrig::CEILING', 408 'argumentCount' => '2' 409 ), 410 'CELL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 411 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 412 'argumentCount' => '1,2' 413 ), 414 'CHAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 415 'functionCall' => 'PHPExcel_Calculation_TextData::CHARACTER', 416 'argumentCount' => '1' 417 ), 418 'CHIDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 419 'functionCall' => 'PHPExcel_Calculation_Statistical::CHIDIST', 420 'argumentCount' => '2' 421 ), 422 'CHIINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 423 'functionCall' => 'PHPExcel_Calculation_Statistical::CHIINV', 424 'argumentCount' => '2' 425 ), 426 'CHITEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 427 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 428 'argumentCount' => '2' 429 ), 430 'CHOOSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 431 'functionCall' => 'PHPExcel_Calculation_LookupRef::CHOOSE', 432 'argumentCount' => '2+' 433 ), 434 'CLEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 435 'functionCall' => 'PHPExcel_Calculation_TextData::TRIMNONPRINTABLE', 436 'argumentCount' => '1' 437 ), 438 'CODE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 439 'functionCall' => 'PHPExcel_Calculation_TextData::ASCIICODE', 440 'argumentCount' => '1' 441 ), 442 'COLUMN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 443 'functionCall' => 'PHPExcel_Calculation_LookupRef::COLUMN', 444 'argumentCount' => '-1', 445 'passByReference' => array(TRUE) 446 ), 447 'COLUMNS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 448 'functionCall' => 'PHPExcel_Calculation_LookupRef::COLUMNS', 449 'argumentCount' => '1' 450 ), 451 'COMBIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 452 'functionCall' => 'PHPExcel_Calculation_MathTrig::COMBIN', 453 'argumentCount' => '2' 454 ), 455 'COMPLEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 456 'functionCall' => 'PHPExcel_Calculation_Engineering::COMPLEX', 457 'argumentCount' => '2,3' 458 ), 459 'CONCATENATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 460 'functionCall' => 'PHPExcel_Calculation_TextData::CONCATENATE', 461 'argumentCount' => '1+' 462 ), 463 'CONFIDENCE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 464 'functionCall' => 'PHPExcel_Calculation_Statistical::CONFIDENCE', 465 'argumentCount' => '3' 466 ), 467 'CONVERT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 468 'functionCall' => 'PHPExcel_Calculation_Engineering::CONVERTUOM', 469 'argumentCount' => '3' 470 ), 471 'CORREL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 472 'functionCall' => 'PHPExcel_Calculation_Statistical::CORREL', 473 'argumentCount' => '2' 474 ), 475 'COS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 476 'functionCall' => 'cos', 477 'argumentCount' => '1' 478 ), 479 'COSH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 480 'functionCall' => 'cosh', 481 'argumentCount' => '1' 482 ), 483 'COUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 484 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNT', 485 'argumentCount' => '1+' 486 ), 487 'COUNTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 488 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTA', 489 'argumentCount' => '1+' 490 ), 491 'COUNTBLANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 492 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTBLANK', 493 'argumentCount' => '1' 494 ), 495 'COUNTIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 496 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTIF', 497 'argumentCount' => '2' 498 ), 499 'COUNTIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 500 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 501 'argumentCount' => '2' 502 ), 503 'COUPDAYBS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 504 'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYBS', 505 'argumentCount' => '3,4' 506 ), 507 'COUPDAYS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 508 'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYS', 509 'argumentCount' => '3,4' 510 ), 511 'COUPDAYSNC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 512 'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYSNC', 513 'argumentCount' => '3,4' 514 ), 515 'COUPNCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 516 'functionCall' => 'PHPExcel_Calculation_Financial::COUPNCD', 517 'argumentCount' => '3,4' 518 ), 519 'COUPNUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 520 'functionCall' => 'PHPExcel_Calculation_Financial::COUPNUM', 521 'argumentCount' => '3,4' 522 ), 523 'COUPPCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 524 'functionCall' => 'PHPExcel_Calculation_Financial::COUPPCD', 525 'argumentCount' => '3,4' 526 ), 527 'COVAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 528 'functionCall' => 'PHPExcel_Calculation_Statistical::COVAR', 529 'argumentCount' => '2' 530 ), 531 'CRITBINOM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 532 'functionCall' => 'PHPExcel_Calculation_Statistical::CRITBINOM', 533 'argumentCount' => '3' 534 ), 535 'CUBEKPIMEMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE, 536 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 537 'argumentCount' => '?' 538 ), 539 'CUBEMEMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE, 540 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 541 'argumentCount' => '?' 542 ), 543 'CUBEMEMBERPROPERTY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE, 544 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 545 'argumentCount' => '?' 546 ), 547 'CUBERANKEDMEMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE, 548 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 549 'argumentCount' => '?' 550 ), 551 'CUBESET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE, 552 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 553 'argumentCount' => '?' 554 ), 555 'CUBESETCOUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE, 556 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 557 'argumentCount' => '?' 558 ), 559 'CUBEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE, 560 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 561 'argumentCount' => '?' 562 ), 563 'CUMIPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 564 'functionCall' => 'PHPExcel_Calculation_Financial::CUMIPMT', 565 'argumentCount' => '6' 566 ), 567 'CUMPRINC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 568 'functionCall' => 'PHPExcel_Calculation_Financial::CUMPRINC', 569 'argumentCount' => '6' 570 ), 571 'DATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 572 'functionCall' => 'PHPExcel_Calculation_DateTime::DATE', 573 'argumentCount' => '3' 574 ), 575 'DATEDIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 576 'functionCall' => 'PHPExcel_Calculation_DateTime::DATEDIF', 577 'argumentCount' => '2,3' 578 ), 579 'DATEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 580 'functionCall' => 'PHPExcel_Calculation_DateTime::DATEVALUE', 581 'argumentCount' => '1' 582 ), 583 'DAVERAGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 584 'functionCall' => 'PHPExcel_Calculation_Database::DAVERAGE', 585 'argumentCount' => '3' 586 ), 587 'DAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 588 'functionCall' => 'PHPExcel_Calculation_DateTime::DAYOFMONTH', 589 'argumentCount' => '1' 590 ), 591 'DAYS360' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 592 'functionCall' => 'PHPExcel_Calculation_DateTime::DAYS360', 593 'argumentCount' => '2,3' 594 ), 595 'DB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 596 'functionCall' => 'PHPExcel_Calculation_Financial::DB', 597 'argumentCount' => '4,5' 598 ), 599 'DCOUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 600 'functionCall' => 'PHPExcel_Calculation_Database::DCOUNT', 601 'argumentCount' => '3' 602 ), 603 'DCOUNTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 604 'functionCall' => 'PHPExcel_Calculation_Database::DCOUNTA', 605 'argumentCount' => '3' 606 ), 607 'DDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 608 'functionCall' => 'PHPExcel_Calculation_Financial::DDB', 609 'argumentCount' => '4,5' 610 ), 611 'DEC2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 612 'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOBIN', 613 'argumentCount' => '1,2' 614 ), 615 'DEC2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 616 'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOHEX', 617 'argumentCount' => '1,2' 618 ), 619 'DEC2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 620 'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOOCT', 621 'argumentCount' => '1,2' 622 ), 623 'DEGREES' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 624 'functionCall' => 'rad2deg', 625 'argumentCount' => '1' 626 ), 627 'DELTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 628 'functionCall' => 'PHPExcel_Calculation_Engineering::DELTA', 629 'argumentCount' => '1,2' 630 ), 631 'DEVSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 632 'functionCall' => 'PHPExcel_Calculation_Statistical::DEVSQ', 633 'argumentCount' => '1+' 634 ), 635 'DGET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 636 'functionCall' => 'PHPExcel_Calculation_Database::DGET', 637 'argumentCount' => '3' 638 ), 639 'DISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 640 'functionCall' => 'PHPExcel_Calculation_Financial::DISC', 641 'argumentCount' => '4,5' 642 ), 643 'DMAX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 644 'functionCall' => 'PHPExcel_Calculation_Database::DMAX', 645 'argumentCount' => '3' 646 ), 647 'DMIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 648 'functionCall' => 'PHPExcel_Calculation_Database::DMIN', 649 'argumentCount' => '3' 650 ), 651 'DOLLAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 652 'functionCall' => 'PHPExcel_Calculation_TextData::DOLLAR', 653 'argumentCount' => '1,2' 654 ), 655 'DOLLARDE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 656 'functionCall' => 'PHPExcel_Calculation_Financial::DOLLARDE', 657 'argumentCount' => '2' 658 ), 659 'DOLLARFR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 660 'functionCall' => 'PHPExcel_Calculation_Financial::DOLLARFR', 661 'argumentCount' => '2' 662 ), 663 'DPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 664 'functionCall' => 'PHPExcel_Calculation_Database::DPRODUCT', 665 'argumentCount' => '3' 666 ), 667 'DSTDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 668 'functionCall' => 'PHPExcel_Calculation_Database::DSTDEV', 669 'argumentCount' => '3' 670 ), 671 'DSTDEVP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 672 'functionCall' => 'PHPExcel_Calculation_Database::DSTDEVP', 673 'argumentCount' => '3' 674 ), 675 'DSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 676 'functionCall' => 'PHPExcel_Calculation_Database::DSUM', 677 'argumentCount' => '3' 678 ), 679 'DURATION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 680 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 681 'argumentCount' => '5,6' 682 ), 683 'DVAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 684 'functionCall' => 'PHPExcel_Calculation_Database::DVAR', 685 'argumentCount' => '3' 686 ), 687 'DVARP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, 688 'functionCall' => 'PHPExcel_Calculation_Database::DVARP', 689 'argumentCount' => '3' 690 ), 691 'EDATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 692 'functionCall' => 'PHPExcel_Calculation_DateTime::EDATE', 693 'argumentCount' => '2' 694 ), 695 'EFFECT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 696 'functionCall' => 'PHPExcel_Calculation_Financial::EFFECT', 697 'argumentCount' => '2' 698 ), 699 'EOMONTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 700 'functionCall' => 'PHPExcel_Calculation_DateTime::EOMONTH', 701 'argumentCount' => '2' 702 ), 703 'ERF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 704 'functionCall' => 'PHPExcel_Calculation_Engineering::ERF', 705 'argumentCount' => '1,2' 706 ), 707 'ERFC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 708 'functionCall' => 'PHPExcel_Calculation_Engineering::ERFC', 709 'argumentCount' => '1' 710 ), 711 'ERROR.TYPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 712 'functionCall' => 'PHPExcel_Calculation_Functions::ERROR_TYPE', 713 'argumentCount' => '1' 714 ), 715 'EVEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 716 'functionCall' => 'PHPExcel_Calculation_MathTrig::EVEN', 717 'argumentCount' => '1' 718 ), 719 'EXACT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 720 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 721 'argumentCount' => '2' 722 ), 723 'EXP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 724 'functionCall' => 'exp', 725 'argumentCount' => '1' 726 ), 727 'EXPONDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 728 'functionCall' => 'PHPExcel_Calculation_Statistical::EXPONDIST', 729 'argumentCount' => '3' 730 ), 731 'FACT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 732 'functionCall' => 'PHPExcel_Calculation_MathTrig::FACT', 733 'argumentCount' => '1' 734 ), 735 'FACTDOUBLE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 736 'functionCall' => 'PHPExcel_Calculation_MathTrig::FACTDOUBLE', 737 'argumentCount' => '1' 738 ), 739 'FALSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, 740 'functionCall' => 'PHPExcel_Calculation_Logical::FALSE', 741 'argumentCount' => '0' 742 ), 743 'FDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 744 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 745 'argumentCount' => '3' 746 ), 747 'FIND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 748 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHSENSITIVE', 749 'argumentCount' => '2,3' 750 ), 751 'FINDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 752 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHSENSITIVE', 753 'argumentCount' => '2,3' 754 ), 755 'FINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 756 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 757 'argumentCount' => '3' 758 ), 759 'FISHER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 760 'functionCall' => 'PHPExcel_Calculation_Statistical::FISHER', 761 'argumentCount' => '1' 762 ), 763 'FISHERINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 764 'functionCall' => 'PHPExcel_Calculation_Statistical::FISHERINV', 765 'argumentCount' => '1' 766 ), 767 'FIXED' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 768 'functionCall' => 'PHPExcel_Calculation_TextData::FIXEDFORMAT', 769 'argumentCount' => '1-3' 770 ), 771 'FLOOR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 772 'functionCall' => 'PHPExcel_Calculation_MathTrig::FLOOR', 773 'argumentCount' => '2' 774 ), 775 'FORECAST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 776 'functionCall' => 'PHPExcel_Calculation_Statistical::FORECAST', 777 'argumentCount' => '3' 778 ), 779 'FREQUENCY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 780 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 781 'argumentCount' => '2' 782 ), 783 'FTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 784 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 785 'argumentCount' => '2' 786 ), 787 'FV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 788 'functionCall' => 'PHPExcel_Calculation_Financial::FV', 789 'argumentCount' => '3-5' 790 ), 791 'FVSCHEDULE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 792 'functionCall' => 'PHPExcel_Calculation_Financial::FVSCHEDULE', 793 'argumentCount' => '2' 794 ), 795 'GAMMADIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 796 'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMADIST', 797 'argumentCount' => '4' 798 ), 799 'GAMMAINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 800 'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMAINV', 801 'argumentCount' => '3' 802 ), 803 'GAMMALN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 804 'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMALN', 805 'argumentCount' => '1' 806 ), 807 'GCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 808 'functionCall' => 'PHPExcel_Calculation_MathTrig::GCD', 809 'argumentCount' => '1+' 810 ), 811 'GEOMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 812 'functionCall' => 'PHPExcel_Calculation_Statistical::GEOMEAN', 813 'argumentCount' => '1+' 814 ), 815 'GESTEP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 816 'functionCall' => 'PHPExcel_Calculation_Engineering::GESTEP', 817 'argumentCount' => '1,2' 818 ), 819 'GETPIVOTDATA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 820 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 821 'argumentCount' => '2+' 822 ), 823 'GROWTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 824 'functionCall' => 'PHPExcel_Calculation_Statistical::GROWTH', 825 'argumentCount' => '1-4' 826 ), 827 'HARMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 828 'functionCall' => 'PHPExcel_Calculation_Statistical::HARMEAN', 829 'argumentCount' => '1+' 830 ), 831 'HEX2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 832 'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTOBIN', 833 'argumentCount' => '1,2' 834 ), 835 'HEX2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 836 'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTODEC', 837 'argumentCount' => '1' 838 ), 839 'HEX2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 840 'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTOOCT', 841 'argumentCount' => '1,2' 842 ), 843 'HLOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 844 'functionCall' => 'PHPExcel_Calculation_LookupRef::HLOOKUP', 845 'argumentCount' => '3,4' 846 ), 847 'HOUR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 848 'functionCall' => 'PHPExcel_Calculation_DateTime::HOUROFDAY', 849 'argumentCount' => '1' 850 ), 851 'HYPERLINK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 852 'functionCall' => 'PHPExcel_Calculation_LookupRef::HYPERLINK', 853 'argumentCount' => '1,2', 854 'passCellReference'=> TRUE 855 ), 856 'HYPGEOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 857 'functionCall' => 'PHPExcel_Calculation_Statistical::HYPGEOMDIST', 858 'argumentCount' => '4' 859 ), 860 'IF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, 861 'functionCall' => 'PHPExcel_Calculation_Logical::STATEMENT_IF', 862 'argumentCount' => '1-3' 863 ), 864 'IFERROR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, 865 'functionCall' => 'PHPExcel_Calculation_Logical::IFERROR', 866 'argumentCount' => '2' 867 ), 868 'IMABS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 869 'functionCall' => 'PHPExcel_Calculation_Engineering::IMABS', 870 'argumentCount' => '1' 871 ), 872 'IMAGINARY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 873 'functionCall' => 'PHPExcel_Calculation_Engineering::IMAGINARY', 874 'argumentCount' => '1' 875 ), 876 'IMARGUMENT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 877 'functionCall' => 'PHPExcel_Calculation_Engineering::IMARGUMENT', 878 'argumentCount' => '1' 879 ), 880 'IMCONJUGATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 881 'functionCall' => 'PHPExcel_Calculation_Engineering::IMCONJUGATE', 882 'argumentCount' => '1' 883 ), 884 'IMCOS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 885 'functionCall' => 'PHPExcel_Calculation_Engineering::IMCOS', 886 'argumentCount' => '1' 887 ), 888 'IMDIV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 889 'functionCall' => 'PHPExcel_Calculation_Engineering::IMDIV', 890 'argumentCount' => '2' 891 ), 892 'IMEXP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 893 'functionCall' => 'PHPExcel_Calculation_Engineering::IMEXP', 894 'argumentCount' => '1' 895 ), 896 'IMLN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 897 'functionCall' => 'PHPExcel_Calculation_Engineering::IMLN', 898 'argumentCount' => '1' 899 ), 900 'IMLOG10' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 901 'functionCall' => 'PHPExcel_Calculation_Engineering::IMLOG10', 902 'argumentCount' => '1' 903 ), 904 'IMLOG2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 905 'functionCall' => 'PHPExcel_Calculation_Engineering::IMLOG2', 906 'argumentCount' => '1' 907 ), 908 'IMPOWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 909 'functionCall' => 'PHPExcel_Calculation_Engineering::IMPOWER', 910 'argumentCount' => '2' 911 ), 912 'IMPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 913 'functionCall' => 'PHPExcel_Calculation_Engineering::IMPRODUCT', 914 'argumentCount' => '1+' 915 ), 916 'IMREAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 917 'functionCall' => 'PHPExcel_Calculation_Engineering::IMREAL', 918 'argumentCount' => '1' 919 ), 920 'IMSIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 921 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSIN', 922 'argumentCount' => '1' 923 ), 924 'IMSQRT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 925 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSQRT', 926 'argumentCount' => '1' 927 ), 928 'IMSUB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 929 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSUB', 930 'argumentCount' => '2' 931 ), 932 'IMSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 933 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSUM', 934 'argumentCount' => '1+' 935 ), 936 'INDEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 937 'functionCall' => 'PHPExcel_Calculation_LookupRef::INDEX', 938 'argumentCount' => '1-4' 939 ), 940 'INDIRECT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 941 'functionCall' => 'PHPExcel_Calculation_LookupRef::INDIRECT', 942 'argumentCount' => '1,2', 943 'passCellReference'=> TRUE 944 ), 945 'INFO' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 946 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 947 'argumentCount' => '1' 948 ), 949 'INT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 950 'functionCall' => 'PHPExcel_Calculation_MathTrig::INT', 951 'argumentCount' => '1' 952 ), 953 'INTERCEPT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 954 'functionCall' => 'PHPExcel_Calculation_Statistical::INTERCEPT', 955 'argumentCount' => '2' 956 ), 957 'INTRATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 958 'functionCall' => 'PHPExcel_Calculation_Financial::INTRATE', 959 'argumentCount' => '4,5' 960 ), 961 'IPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 962 'functionCall' => 'PHPExcel_Calculation_Financial::IPMT', 963 'argumentCount' => '4-6' 964 ), 965 'IRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 966 'functionCall' => 'PHPExcel_Calculation_Financial::IRR', 967 'argumentCount' => '1,2' 968 ), 969 'ISBLANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 970 'functionCall' => 'PHPExcel_Calculation_Functions::IS_BLANK', 971 'argumentCount' => '1' 972 ), 973 'ISERR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 974 'functionCall' => 'PHPExcel_Calculation_Functions::IS_ERR', 975 'argumentCount' => '1' 976 ), 977 'ISERROR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 978 'functionCall' => 'PHPExcel_Calculation_Functions::IS_ERROR', 979 'argumentCount' => '1' 980 ), 981 'ISEVEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 982 'functionCall' => 'PHPExcel_Calculation_Functions::IS_EVEN', 983 'argumentCount' => '1' 984 ), 985 'ISLOGICAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 986 'functionCall' => 'PHPExcel_Calculation_Functions::IS_LOGICAL', 987 'argumentCount' => '1' 988 ), 989 'ISNA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 990 'functionCall' => 'PHPExcel_Calculation_Functions::IS_NA', 991 'argumentCount' => '1' 992 ), 993 'ISNONTEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 994 'functionCall' => 'PHPExcel_Calculation_Functions::IS_NONTEXT', 995 'argumentCount' => '1' 996 ), 997 'ISNUMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 998 'functionCall' => 'PHPExcel_Calculation_Functions::IS_NUMBER', 999 'argumentCount' => '1' 1000 ), 1001 'ISODD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 1002 'functionCall' => 'PHPExcel_Calculation_Functions::IS_ODD', 1003 'argumentCount' => '1' 1004 ), 1005 'ISPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1006 'functionCall' => 'PHPExcel_Calculation_Financial::ISPMT', 1007 'argumentCount' => '4' 1008 ), 1009 'ISREF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 1010 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1011 'argumentCount' => '1' 1012 ), 1013 'ISTEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 1014 'functionCall' => 'PHPExcel_Calculation_Functions::IS_TEXT', 1015 'argumentCount' => '1' 1016 ), 1017 'JIS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1018 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1019 'argumentCount' => '1' 1020 ), 1021 'KURT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1022 'functionCall' => 'PHPExcel_Calculation_Statistical::KURT', 1023 'argumentCount' => '1+' 1024 ), 1025 'LARGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1026 'functionCall' => 'PHPExcel_Calculation_Statistical::LARGE', 1027 'argumentCount' => '2' 1028 ), 1029 'LCM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1030 'functionCall' => 'PHPExcel_Calculation_MathTrig::LCM', 1031 'argumentCount' => '1+' 1032 ), 1033 'LEFT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1034 'functionCall' => 'PHPExcel_Calculation_TextData::LEFT', 1035 'argumentCount' => '1,2' 1036 ), 1037 'LEFTB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1038 'functionCall' => 'PHPExcel_Calculation_TextData::LEFT', 1039 'argumentCount' => '1,2' 1040 ), 1041 'LEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1042 'functionCall' => 'PHPExcel_Calculation_TextData::STRINGLENGTH', 1043 'argumentCount' => '1' 1044 ), 1045 'LENB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1046 'functionCall' => 'PHPExcel_Calculation_TextData::STRINGLENGTH', 1047 'argumentCount' => '1' 1048 ), 1049 'LINEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1050 'functionCall' => 'PHPExcel_Calculation_Statistical::LINEST', 1051 'argumentCount' => '1-4' 1052 ), 1053 'LN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1054 'functionCall' => 'log', 1055 'argumentCount' => '1' 1056 ), 1057 'LOG' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1058 'functionCall' => 'PHPExcel_Calculation_MathTrig::LOG_BASE', 1059 'argumentCount' => '1,2' 1060 ), 1061 'LOG10' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1062 'functionCall' => 'log10', 1063 'argumentCount' => '1' 1064 ), 1065 'LOGEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1066 'functionCall' => 'PHPExcel_Calculation_Statistical::LOGEST', 1067 'argumentCount' => '1-4' 1068 ), 1069 'LOGINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1070 'functionCall' => 'PHPExcel_Calculation_Statistical::LOGINV', 1071 'argumentCount' => '3' 1072 ), 1073 'LOGNORMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1074 'functionCall' => 'PHPExcel_Calculation_Statistical::LOGNORMDIST', 1075 'argumentCount' => '3' 1076 ), 1077 'LOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 1078 'functionCall' => 'PHPExcel_Calculation_LookupRef::LOOKUP', 1079 'argumentCount' => '2,3' 1080 ), 1081 'LOWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1082 'functionCall' => 'PHPExcel_Calculation_TextData::LOWERCASE', 1083 'argumentCount' => '1' 1084 ), 1085 'MATCH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 1086 'functionCall' => 'PHPExcel_Calculation_LookupRef::MATCH', 1087 'argumentCount' => '2,3' 1088 ), 1089 'MAX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1090 'functionCall' => 'PHPExcel_Calculation_Statistical::MAX', 1091 'argumentCount' => '1+' 1092 ), 1093 'MAXA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1094 'functionCall' => 'PHPExcel_Calculation_Statistical::MAXA', 1095 'argumentCount' => '1+' 1096 ), 1097 'MAXIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1098 'functionCall' => 'PHPExcel_Calculation_Statistical::MAXIF', 1099 'argumentCount' => '2+' 1100 ), 1101 'MDETERM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1102 'functionCall' => 'PHPExcel_Calculation_MathTrig::MDETERM', 1103 'argumentCount' => '1' 1104 ), 1105 'MDURATION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1106 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1107 'argumentCount' => '5,6' 1108 ), 1109 'MEDIAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1110 'functionCall' => 'PHPExcel_Calculation_Statistical::MEDIAN', 1111 'argumentCount' => '1+' 1112 ), 1113 'MEDIANIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1114 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1115 'argumentCount' => '2+' 1116 ), 1117 'MID' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1118 'functionCall' => 'PHPExcel_Calculation_TextData::MID', 1119 'argumentCount' => '3' 1120 ), 1121 'MIDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1122 'functionCall' => 'PHPExcel_Calculation_TextData::MID', 1123 'argumentCount' => '3' 1124 ), 1125 'MIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1126 'functionCall' => 'PHPExcel_Calculation_Statistical::MIN', 1127 'argumentCount' => '1+' 1128 ), 1129 'MINA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1130 'functionCall' => 'PHPExcel_Calculation_Statistical::MINA', 1131 'argumentCount' => '1+' 1132 ), 1133 'MINIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1134 'functionCall' => 'PHPExcel_Calculation_Statistical::MINIF', 1135 'argumentCount' => '2+' 1136 ), 1137 'MINUTE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1138 'functionCall' => 'PHPExcel_Calculation_DateTime::MINUTEOFHOUR', 1139 'argumentCount' => '1' 1140 ), 1141 'MINVERSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1142 'functionCall' => 'PHPExcel_Calculation_MathTrig::MINVERSE', 1143 'argumentCount' => '1' 1144 ), 1145 'MIRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1146 'functionCall' => 'PHPExcel_Calculation_Financial::MIRR', 1147 'argumentCount' => '3' 1148 ), 1149 'MMULT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1150 'functionCall' => 'PHPExcel_Calculation_MathTrig::MMULT', 1151 'argumentCount' => '2' 1152 ), 1153 'MOD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1154 'functionCall' => 'PHPExcel_Calculation_MathTrig::MOD', 1155 'argumentCount' => '2' 1156 ), 1157 'MODE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1158 'functionCall' => 'PHPExcel_Calculation_Statistical::MODE', 1159 'argumentCount' => '1+' 1160 ), 1161 'MONTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1162 'functionCall' => 'PHPExcel_Calculation_DateTime::MONTHOFYEAR', 1163 'argumentCount' => '1' 1164 ), 1165 'MROUND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1166 'functionCall' => 'PHPExcel_Calculation_MathTrig::MROUND', 1167 'argumentCount' => '2' 1168 ), 1169 'MULTINOMIAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1170 'functionCall' => 'PHPExcel_Calculation_MathTrig::MULTINOMIAL', 1171 'argumentCount' => '1+' 1172 ), 1173 'N' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 1174 'functionCall' => 'PHPExcel_Calculation_Functions::N', 1175 'argumentCount' => '1' 1176 ), 1177 'NA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 1178 'functionCall' => 'PHPExcel_Calculation_Functions::NA', 1179 'argumentCount' => '0' 1180 ), 1181 'NEGBINOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1182 'functionCall' => 'PHPExcel_Calculation_Statistical::NEGBINOMDIST', 1183 'argumentCount' => '3' 1184 ), 1185 'NETWORKDAYS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1186 'functionCall' => 'PHPExcel_Calculation_DateTime::NETWORKDAYS', 1187 'argumentCount' => '2+' 1188 ), 1189 'NOMINAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1190 'functionCall' => 'PHPExcel_Calculation_Financial::NOMINAL', 1191 'argumentCount' => '2' 1192 ), 1193 'NORMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1194 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMDIST', 1195 'argumentCount' => '4' 1196 ), 1197 'NORMINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1198 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMINV', 1199 'argumentCount' => '3' 1200 ), 1201 'NORMSDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1202 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMSDIST', 1203 'argumentCount' => '1' 1204 ), 1205 'NORMSINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1206 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMSINV', 1207 'argumentCount' => '1' 1208 ), 1209 'NOT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, 1210 'functionCall' => 'PHPExcel_Calculation_Logical::NOT', 1211 'argumentCount' => '1' 1212 ), 1213 'NOW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1214 'functionCall' => 'PHPExcel_Calculation_DateTime::DATETIMENOW', 1215 'argumentCount' => '0' 1216 ), 1217 'NPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1218 'functionCall' => 'PHPExcel_Calculation_Financial::NPER', 1219 'argumentCount' => '3-5' 1220 ), 1221 'NPV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1222 'functionCall' => 'PHPExcel_Calculation_Financial::NPV', 1223 'argumentCount' => '2+' 1224 ), 1225 'OCT2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 1226 'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTOBIN', 1227 'argumentCount' => '1,2' 1228 ), 1229 'OCT2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 1230 'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTODEC', 1231 'argumentCount' => '1' 1232 ), 1233 'OCT2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, 1234 'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTOHEX', 1235 'argumentCount' => '1,2' 1236 ), 1237 'ODD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1238 'functionCall' => 'PHPExcel_Calculation_MathTrig::ODD', 1239 'argumentCount' => '1' 1240 ), 1241 'ODDFPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1242 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1243 'argumentCount' => '8,9' 1244 ), 1245 'ODDFYIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1246 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1247 'argumentCount' => '8,9' 1248 ), 1249 'ODDLPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1250 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1251 'argumentCount' => '7,8' 1252 ), 1253 'ODDLYIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1254 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1255 'argumentCount' => '7,8' 1256 ), 1257 'OFFSET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 1258 'functionCall' => 'PHPExcel_Calculation_LookupRef::OFFSET', 1259 'argumentCount' => '3,5', 1260 'passCellReference'=> TRUE, 1261 'passByReference' => array(TRUE) 1262 ), 1263 'OR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, 1264 'functionCall' => 'PHPExcel_Calculation_Logical::LOGICAL_OR', 1265 'argumentCount' => '1+' 1266 ), 1267 'PEARSON' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1268 'functionCall' => 'PHPExcel_Calculation_Statistical::CORREL', 1269 'argumentCount' => '2' 1270 ), 1271 'PERCENTILE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1272 'functionCall' => 'PHPExcel_Calculation_Statistical::PERCENTILE', 1273 'argumentCount' => '2' 1274 ), 1275 'PERCENTRANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1276 'functionCall' => 'PHPExcel_Calculation_Statistical::PERCENTRANK', 1277 'argumentCount' => '2,3' 1278 ), 1279 'PERMUT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1280 'functionCall' => 'PHPExcel_Calculation_Statistical::PERMUT', 1281 'argumentCount' => '2' 1282 ), 1283 'PHONETIC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1284 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1285 'argumentCount' => '1' 1286 ), 1287 'PI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1288 'functionCall' => 'pi', 1289 'argumentCount' => '0' 1290 ), 1291 'PMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1292 'functionCall' => 'PHPExcel_Calculation_Financial::PMT', 1293 'argumentCount' => '3-5' 1294 ), 1295 'POISSON' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1296 'functionCall' => 'PHPExcel_Calculation_Statistical::POISSON', 1297 'argumentCount' => '3' 1298 ), 1299 'POWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1300 'functionCall' => 'PHPExcel_Calculation_MathTrig::POWER', 1301 'argumentCount' => '2' 1302 ), 1303 'PPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1304 'functionCall' => 'PHPExcel_Calculation_Financial::PPMT', 1305 'argumentCount' => '4-6' 1306 ), 1307 'PRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1308 'functionCall' => 'PHPExcel_Calculation_Financial::PRICE', 1309 'argumentCount' => '6,7' 1310 ), 1311 'PRICEDISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1312 'functionCall' => 'PHPExcel_Calculation_Financial::PRICEDISC', 1313 'argumentCount' => '4,5' 1314 ), 1315 'PRICEMAT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1316 'functionCall' => 'PHPExcel_Calculation_Financial::PRICEMAT', 1317 'argumentCount' => '5,6' 1318 ), 1319 'PROB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1320 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1321 'argumentCount' => '3,4' 1322 ), 1323 'PRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1324 'functionCall' => 'PHPExcel_Calculation_MathTrig::PRODUCT', 1325 'argumentCount' => '1+' 1326 ), 1327 'PROPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1328 'functionCall' => 'PHPExcel_Calculation_TextData::PROPERCASE', 1329 'argumentCount' => '1' 1330 ), 1331 'PV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1332 'functionCall' => 'PHPExcel_Calculation_Financial::PV', 1333 'argumentCount' => '3-5' 1334 ), 1335 'QUARTILE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1336 'functionCall' => 'PHPExcel_Calculation_Statistical::QUARTILE', 1337 'argumentCount' => '2' 1338 ), 1339 'QUOTIENT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1340 'functionCall' => 'PHPExcel_Calculation_MathTrig::QUOTIENT', 1341 'argumentCount' => '2' 1342 ), 1343 'RADIANS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1344 'functionCall' => 'deg2rad', 1345 'argumentCount' => '1' 1346 ), 1347 'RAND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1348 'functionCall' => 'PHPExcel_Calculation_MathTrig::RAND', 1349 'argumentCount' => '0' 1350 ), 1351 'RANDBETWEEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1352 'functionCall' => 'PHPExcel_Calculation_MathTrig::RAND', 1353 'argumentCount' => '2' 1354 ), 1355 'RANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1356 'functionCall' => 'PHPExcel_Calculation_Statistical::RANK', 1357 'argumentCount' => '2,3' 1358 ), 1359 'RATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1360 'functionCall' => 'PHPExcel_Calculation_Financial::RATE', 1361 'argumentCount' => '3-6' 1362 ), 1363 'RECEIVED' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1364 'functionCall' => 'PHPExcel_Calculation_Financial::RECEIVED', 1365 'argumentCount' => '4-5' 1366 ), 1367 'REPLACE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1368 'functionCall' => 'PHPExcel_Calculation_TextData::REPLACE', 1369 'argumentCount' => '4' 1370 ), 1371 'REPLACEB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1372 'functionCall' => 'PHPExcel_Calculation_TextData::REPLACE', 1373 'argumentCount' => '4' 1374 ), 1375 'REPT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1376 'functionCall' => 'str_repeat', 1377 'argumentCount' => '2' 1378 ), 1379 'RIGHT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1380 'functionCall' => 'PHPExcel_Calculation_TextData::RIGHT', 1381 'argumentCount' => '1,2' 1382 ), 1383 'RIGHTB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1384 'functionCall' => 'PHPExcel_Calculation_TextData::RIGHT', 1385 'argumentCount' => '1,2' 1386 ), 1387 'ROMAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1388 'functionCall' => 'PHPExcel_Calculation_MathTrig::ROMAN', 1389 'argumentCount' => '1,2' 1390 ), 1391 'ROUND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1392 'functionCall' => 'round', 1393 'argumentCount' => '2' 1394 ), 1395 'ROUNDDOWN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1396 'functionCall' => 'PHPExcel_Calculation_MathTrig::ROUNDDOWN', 1397 'argumentCount' => '2' 1398 ), 1399 'ROUNDUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1400 'functionCall' => 'PHPExcel_Calculation_MathTrig::ROUNDUP', 1401 'argumentCount' => '2' 1402 ), 1403 'ROW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 1404 'functionCall' => 'PHPExcel_Calculation_LookupRef::ROW', 1405 'argumentCount' => '-1', 1406 'passByReference' => array(TRUE) 1407 ), 1408 'ROWS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 1409 'functionCall' => 'PHPExcel_Calculation_LookupRef::ROWS', 1410 'argumentCount' => '1' 1411 ), 1412 'RSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1413 'functionCall' => 'PHPExcel_Calculation_Statistical::RSQ', 1414 'argumentCount' => '2' 1415 ), 1416 'RTD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 1417 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1418 'argumentCount' => '1+' 1419 ), 1420 'SEARCH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1421 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHINSENSITIVE', 1422 'argumentCount' => '2,3' 1423 ), 1424 'SEARCHB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1425 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHINSENSITIVE', 1426 'argumentCount' => '2,3' 1427 ), 1428 'SECOND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1429 'functionCall' => 'PHPExcel_Calculation_DateTime::SECONDOFMINUTE', 1430 'argumentCount' => '1' 1431 ), 1432 'SERIESSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1433 'functionCall' => 'PHPExcel_Calculation_MathTrig::SERIESSUM', 1434 'argumentCount' => '4' 1435 ), 1436 'SIGN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1437 'functionCall' => 'PHPExcel_Calculation_MathTrig::SIGN', 1438 'argumentCount' => '1' 1439 ), 1440 'SIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1441 'functionCall' => 'sin', 1442 'argumentCount' => '1' 1443 ), 1444 'SINH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1445 'functionCall' => 'sinh', 1446 'argumentCount' => '1' 1447 ), 1448 'SKEW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1449 'functionCall' => 'PHPExcel_Calculation_Statistical::SKEW', 1450 'argumentCount' => '1+' 1451 ), 1452 'SLN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1453 'functionCall' => 'PHPExcel_Calculation_Financial::SLN', 1454 'argumentCount' => '3' 1455 ), 1456 'SLOPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1457 'functionCall' => 'PHPExcel_Calculation_Statistical::SLOPE', 1458 'argumentCount' => '2' 1459 ), 1460 'SMALL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1461 'functionCall' => 'PHPExcel_Calculation_Statistical::SMALL', 1462 'argumentCount' => '2' 1463 ), 1464 'SQRT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1465 'functionCall' => 'sqrt', 1466 'argumentCount' => '1' 1467 ), 1468 'SQRTPI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1469 'functionCall' => 'PHPExcel_Calculation_MathTrig::SQRTPI', 1470 'argumentCount' => '1' 1471 ), 1472 'STANDARDIZE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1473 'functionCall' => 'PHPExcel_Calculation_Statistical::STANDARDIZE', 1474 'argumentCount' => '3' 1475 ), 1476 'STDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1477 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEV', 1478 'argumentCount' => '1+' 1479 ), 1480 'STDEVA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1481 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVA', 1482 'argumentCount' => '1+' 1483 ), 1484 'STDEVP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1485 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVP', 1486 'argumentCount' => '1+' 1487 ), 1488 'STDEVPA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1489 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVPA', 1490 'argumentCount' => '1+' 1491 ), 1492 'STEYX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1493 'functionCall' => 'PHPExcel_Calculation_Statistical::STEYX', 1494 'argumentCount' => '2' 1495 ), 1496 'SUBSTITUTE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1497 'functionCall' => 'PHPExcel_Calculation_TextData::SUBSTITUTE', 1498 'argumentCount' => '3,4' 1499 ), 1500 'SUBTOTAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1501 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUBTOTAL', 1502 'argumentCount' => '2+' 1503 ), 1504 'SUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1505 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUM', 1506 'argumentCount' => '1+' 1507 ), 1508 'SUMIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1509 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMIF', 1510 'argumentCount' => '2,3' 1511 ), 1512 'SUMIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1513 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1514 'argumentCount' => '?' 1515 ), 1516 'SUMPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1517 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMPRODUCT', 1518 'argumentCount' => '1+' 1519 ), 1520 'SUMSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1521 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMSQ', 1522 'argumentCount' => '1+' 1523 ), 1524 'SUMX2MY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1525 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMX2MY2', 1526 'argumentCount' => '2' 1527 ), 1528 'SUMX2PY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1529 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMX2PY2', 1530 'argumentCount' => '2' 1531 ), 1532 'SUMXMY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1533 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMXMY2', 1534 'argumentCount' => '2' 1535 ), 1536 'SYD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1537 'functionCall' => 'PHPExcel_Calculation_Financial::SYD', 1538 'argumentCount' => '4' 1539 ), 1540 'T' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1541 'functionCall' => 'PHPExcel_Calculation_TextData::RETURNSTRING', 1542 'argumentCount' => '1' 1543 ), 1544 'TAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1545 'functionCall' => 'tan', 1546 'argumentCount' => '1' 1547 ), 1548 'TANH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1549 'functionCall' => 'tanh', 1550 'argumentCount' => '1' 1551 ), 1552 'TBILLEQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1553 'functionCall' => 'PHPExcel_Calculation_Financial::TBILLEQ', 1554 'argumentCount' => '3' 1555 ), 1556 'TBILLPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1557 'functionCall' => 'PHPExcel_Calculation_Financial::TBILLPRICE', 1558 'argumentCount' => '3' 1559 ), 1560 'TBILLYIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1561 'functionCall' => 'PHPExcel_Calculation_Financial::TBILLYIELD', 1562 'argumentCount' => '3' 1563 ), 1564 'TDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1565 'functionCall' => 'PHPExcel_Calculation_Statistical::TDIST', 1566 'argumentCount' => '3' 1567 ), 1568 'TEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1569 'functionCall' => 'PHPExcel_Calculation_TextData::TEXTFORMAT', 1570 'argumentCount' => '2' 1571 ), 1572 'TIME' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1573 'functionCall' => 'PHPExcel_Calculation_DateTime::TIME', 1574 'argumentCount' => '3' 1575 ), 1576 'TIMEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1577 'functionCall' => 'PHPExcel_Calculation_DateTime::TIMEVALUE', 1578 'argumentCount' => '1' 1579 ), 1580 'TINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1581 'functionCall' => 'PHPExcel_Calculation_Statistical::TINV', 1582 'argumentCount' => '2' 1583 ), 1584 'TODAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1585 'functionCall' => 'PHPExcel_Calculation_DateTime::DATENOW', 1586 'argumentCount' => '0' 1587 ), 1588 'TRANSPOSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 1589 'functionCall' => 'PHPExcel_Calculation_LookupRef::TRANSPOSE', 1590 'argumentCount' => '1' 1591 ), 1592 'TREND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1593 'functionCall' => 'PHPExcel_Calculation_Statistical::TREND', 1594 'argumentCount' => '1-4' 1595 ), 1596 'TRIM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1597 'functionCall' => 'PHPExcel_Calculation_TextData::TRIMSPACES', 1598 'argumentCount' => '1' 1599 ), 1600 'TRIMMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1601 'functionCall' => 'PHPExcel_Calculation_Statistical::TRIMMEAN', 1602 'argumentCount' => '2' 1603 ), 1604 'TRUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, 1605 'functionCall' => 'PHPExcel_Calculation_Logical::TRUE', 1606 'argumentCount' => '0' 1607 ), 1608 'TRUNC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, 1609 'functionCall' => 'PHPExcel_Calculation_MathTrig::TRUNC', 1610 'argumentCount' => '1,2' 1611 ), 1612 'TTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1613 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1614 'argumentCount' => '4' 1615 ), 1616 'TYPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 1617 'functionCall' => 'PHPExcel_Calculation_Functions::TYPE', 1618 'argumentCount' => '1' 1619 ), 1620 'UPPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1621 'functionCall' => 'PHPExcel_Calculation_TextData::UPPERCASE', 1622 'argumentCount' => '1' 1623 ), 1624 'USDOLLAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1625 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1626 'argumentCount' => '2' 1627 ), 1628 'VALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, 1629 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1630 'argumentCount' => '1' 1631 ), 1632 'VAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1633 'functionCall' => 'PHPExcel_Calculation_Statistical::VARFunc', 1634 'argumentCount' => '1+' 1635 ), 1636 'VARA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1637 'functionCall' => 'PHPExcel_Calculation_Statistical::VARA', 1638 'argumentCount' => '1+' 1639 ), 1640 'VARP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1641 'functionCall' => 'PHPExcel_Calculation_Statistical::VARP', 1642 'argumentCount' => '1+' 1643 ), 1644 'VARPA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1645 'functionCall' => 'PHPExcel_Calculation_Statistical::VARPA', 1646 'argumentCount' => '1+' 1647 ), 1648 'VDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1649 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1650 'argumentCount' => '5-7' 1651 ), 1652 'VERSION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 1653 'functionCall' => 'PHPExcel_Calculation_Functions::VERSION', 1654 'argumentCount' => '0' 1655 ), 1656 'VLOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 1657 'functionCall' => 'PHPExcel_Calculation_LookupRef::VLOOKUP', 1658 'argumentCount' => '3,4' 1659 ), 1660 'WEEKDAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1661 'functionCall' => 'PHPExcel_Calculation_DateTime::DAYOFWEEK', 1662 'argumentCount' => '1,2' 1663 ), 1664 'WEEKNUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1665 'functionCall' => 'PHPExcel_Calculation_DateTime::WEEKOFYEAR', 1666 'argumentCount' => '1,2' 1667 ), 1668 'WEIBULL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1669 'functionCall' => 'PHPExcel_Calculation_Statistical::WEIBULL', 1670 'argumentCount' => '4' 1671 ), 1672 'WORKDAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1673 'functionCall' => 'PHPExcel_Calculation_DateTime::WORKDAY', 1674 'argumentCount' => '2+' 1675 ), 1676 'XIRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1677 'functionCall' => 'PHPExcel_Calculation_Financial::XIRR', 1678 'argumentCount' => '2,3' 1679 ), 1680 'XNPV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1681 'functionCall' => 'PHPExcel_Calculation_Financial::XNPV', 1682 'argumentCount' => '3' 1683 ), 1684 'YEAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1685 'functionCall' => 'PHPExcel_Calculation_DateTime::YEAR', 1686 'argumentCount' => '1' 1687 ), 1688 'YEARFRAC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, 1689 'functionCall' => 'PHPExcel_Calculation_DateTime::YEARFRAC', 1690 'argumentCount' => '2,3' 1691 ), 1692 'YIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1693 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', 1694 'argumentCount' => '6,7' 1695 ), 1696 'YIELDDISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1697 'functionCall' => 'PHPExcel_Calculation_Financial::YIELDDISC', 1698 'argumentCount' => '4,5' 1699 ), 1700 'YIELDMAT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, 1701 'functionCall' => 'PHPExcel_Calculation_Financial::YIELDMAT', 1702 'argumentCount' => '5,6' 1703 ), 1704 'ZTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 1705 'functionCall' => 'PHPExcel_Calculation_Statistical::ZTEST', 1706 'argumentCount' => '2-3' 1707 ) 1708 ); 1709 1710 1711 // Internal functions used for special control purposes 1712 private static $_controlFunctions = array( 1713 'MKMATRIX' => array('argumentCount' => '*', 1714 'functionCall' => 'self::_mkMatrix' 1715 ) 1716 ); 1717 1718 1719 1720 1721 private function __construct(PHPExcel $workbook = NULL) { 1722 $setPrecision = (PHP_INT_SIZE == 4) ? 14 : 16; 1723 $this->_savedPrecision = ini_get('precision'); 1724 if ($this->_savedPrecision < $setPrecision) { 1725 ini_set('precision',$setPrecision); 1726 } 1727 1728 if ($workbook !== NULL) { 1729 self::$_workbookSets[$workbook->getID()] = $this; 1730 } 1731 1732 $this->_workbook = $workbook; 1733 $this->_cyclicReferenceStack = new PHPExcel_CalcEngine_CyclicReferenceStack(); 1734 $this->_debugLog = new PHPExcel_CalcEngine_Logger($this->_cyclicReferenceStack); 1735 } // function __construct() 1736 1737 1738 public function __destruct() { 1739 if ($this->_savedPrecision != ini_get('precision')) { 1740 ini_set('precision',$this->_savedPrecision); 1741 } 1742 } 1743 1744 private static function _loadLocales() { 1745 $localeFileDirectory = PHPEXCEL_ROOT.'PHPExcel/locale/'; 1746 foreach (glob($localeFileDirectory.'/*',GLOB_ONLYDIR) as $filename) { 1747 $filename = substr($filename,strlen($localeFileDirectory)+1); 1748 if ($filename != 'en') { 1749 self::$_validLocaleLanguages[] = $filename; 1750 } 1751 } 1752 } 1753 1754 /** 1755 * Get an instance of this class 1756 * 1757 * @access public 1758 * @param PHPExcel $workbook Injected workbook for working with a PHPExcel object, 1759 * or NULL to create a standalone claculation engine 1760 * @return PHPExcel_Calculation 1761 */ 1762 public static function getInstance(PHPExcel $workbook = NULL) { 1763 if ($workbook !== NULL) { 1764 if (isset(self::$_workbookSets[$workbook->getID()])) { 1765 return self::$_workbookSets[$workbook->getID()]; 1766 } 1767 return new PHPExcel_Calculation($workbook); 1768 } 1769 1770 if (!isset(self::$_instance) || (self::$_instance === NULL)) { 1771 self::$_instance = new PHPExcel_Calculation(); 1772 } 1773 1774 return self::$_instance; 1775 } // function getInstance() 1776 1777 /** 1778 * Unset an instance of this class 1779 * 1780 * @access public 1781 * @param PHPExcel $workbook Injected workbook identifying the instance to unset 1782 */ 1783 public static function unsetInstance(PHPExcel $workbook = NULL) { 1784 if ($workbook !== NULL) { 1785 if (isset(self::$_workbookSets[$workbook->getID()])) { 1786 unset(self::$_workbookSets[$workbook->getID()]); 1787 } 1788 } 1789 } 1790 1791 /** 1792 * Flush the calculation cache for any existing instance of this class 1793 * but only if a PHPExcel_Calculation instance exists 1794 * 1795 * @access public 1796 * @return null 1797 */ 1798 public function flushInstance() { 1799 $this->clearCalculationCache(); 1800 } // function flushInstance() 1801 1802 1803 /** 1804 * Get the debuglog for this claculation engine instance 1805 * 1806 * @access public 1807 * @return PHPExcel_CalcEngine_Logger 1808 */ 1809 public function getDebugLog() { 1810 return $this->_debugLog; 1811 } 1812 1813 /** 1814 * __clone implementation. Cloning should not be allowed in a Singleton! 1815 * 1816 * @access public 1817 * @throws PHPExcel_Calculation_Exception 1818 */ 1819 public final function __clone() { 1820 throw new PHPExcel_Calculation_Exception ('Cloning the calculation engine is not allowed!'); 1821 } // function __clone() 1822 1823 1824 /** 1825 * Return the locale-specific translation of TRUE 1826 * 1827 * @access public 1828 * @return string locale-specific translation of TRUE 1829 */ 1830 public static function getTRUE() { 1831 return self::$_localeBoolean['TRUE']; 1832 } 1833 1834 /** 1835 * Return the locale-specific translation of FALSE 1836 * 1837 * @access public 1838 * @return string locale-specific translation of FALSE 1839 */ 1840 public static function getFALSE() { 1841 return self::$_localeBoolean['FALSE']; 1842 } 1843 1844 /** 1845 * Set the Array Return Type (Array or Value of first element in the array) 1846 * 1847 * @access public 1848 * @param string $returnType Array return type 1849 * @return boolean Success or failure 1850 */ 1851 public static function setArrayReturnType($returnType) { 1852 if (($returnType == self::RETURN_ARRAY_AS_VALUE) || 1853 ($returnType == self::RETURN_ARRAY_AS_ERROR) || 1854 ($returnType == self::RETURN_ARRAY_AS_ARRAY)) { 1855 self::$returnArrayAsType = $returnType; 1856 return TRUE; 1857 } 1858 return FALSE; 1859 } // function setArrayReturnType() 1860 1861 1862 /** 1863 * Return the Array Return Type (Array or Value of first element in the array) 1864 * 1865 * @access public 1866 * @return string $returnType Array return type 1867 */ 1868 public static function getArrayReturnType() { 1869 return self::$returnArrayAsType; 1870 } // function getArrayReturnType() 1871 1872 1873 /** 1874 * Is calculation caching enabled? 1875 * 1876 * @access public 1877 * @return boolean 1878 */ 1879 public function getCalculationCacheEnabled() { 1880 return $this->_calculationCacheEnabled; 1881 } // function getCalculationCacheEnabled() 1882 1883 /** 1884 * Enable/disable calculation cache 1885 * 1886 * @access public 1887 * @param boolean $pValue 1888 */ 1889 public function setCalculationCacheEnabled($pValue = TRUE) { 1890 $this->_calculationCacheEnabled = $pValue; 1891 $this->clearCalculationCache(); 1892 } // function setCalculationCacheEnabled() 1893 1894 1895 /** 1896 * Enable calculation cache 1897 */ 1898 public function enableCalculationCache() { 1899 $this->setCalculationCacheEnabled(TRUE); 1900 } // function enableCalculationCache() 1901 1902 1903 /** 1904 * Disable calculation cache 1905 */ 1906 public function disableCalculationCache() { 1907 $this->setCalculationCacheEnabled(FALSE); 1908 } // function disableCalculationCache() 1909 1910 1911 /** 1912 * Clear calculation cache 1913 */ 1914 public function clearCalculationCache() { 1915 $this->_calculationCache = array(); 1916 } // function clearCalculationCache() 1917 1918 /** 1919 * Clear calculation cache for a specified worksheet 1920 * 1921 * @param string $worksheetName 1922 */ 1923 public function clearCalculationCacheForWorksheet($worksheetName) { 1924 if (isset($this->_calculationCache[$worksheetName])) { 1925 unset($this->_calculationCache[$worksheetName]); 1926 } 1927 } // function clearCalculationCacheForWorksheet() 1928 1929 /** 1930 * Rename calculation cache for a specified worksheet 1931 * 1932 * @param string $fromWorksheetName 1933 * @param string $toWorksheetName 1934 */ 1935 public function renameCalculationCacheForWorksheet($fromWorksheetName, $toWorksheetName) { 1936 if (isset($this->_calculationCache[$fromWorksheetName])) { 1937 $this->_calculationCache[$toWorksheetName] = &$this->_calculationCache[$fromWorksheetName]; 1938 unset($this->_calculationCache[$fromWorksheetName]); 1939 } 1940 } // function renameCalculationCacheForWorksheet() 1941 1942 1943 /** 1944 * Get the currently defined locale code 1945 * 1946 * @return string 1947 */ 1948 public function getLocale() { 1949 return self::$_localeLanguage; 1950 } // function getLocale() 1951 1952 1953 /** 1954 * Set the locale code 1955 * 1956 * @param string $locale The locale to use for formula translation 1957 * @return boolean 1958 */ 1959 public function setLocale($locale = 'en_us') { 1960 // Identify our locale and language 1961 $language = $locale = strtolower($locale); 1962 if (strpos($locale,'_') !== FALSE) { 1963 list($language) = explode('_',$locale); 1964 } 1965 1966 if (count(self::$_validLocaleLanguages) == 1) 1967 self::_loadLocales(); 1968 1969 // Test whether we have any language data for this language (any locale) 1970 if (in_array($language,self::$_validLocaleLanguages)) { 1971 // initialise language/locale settings 1972 self::$_localeFunctions = array(); 1973 self::$_localeArgumentSeparator = ','; 1974 self::$_localeBoolean = array('TRUE' => 'TRUE', 'FALSE' => 'FALSE', 'NULL' => 'NULL'); 1975 // Default is English, if user isn't requesting english, then read the necessary data from the locale files 1976 if ($locale != 'en_us') { 1977 // Search for a file with a list of function names for locale 1978 $functionNamesFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.str_replace('_',DIRECTORY_SEPARATOR,$locale).DIRECTORY_SEPARATOR.'functions'; 1979 if (!file_exists($functionNamesFile)) { 1980 // If there isn't a locale specific function file, look for a language specific function file 1981 $functionNamesFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.'functions'; 1982 if (!file_exists($functionNamesFile)) { 1983 return FALSE; 1984 } 1985 } 1986 // Retrieve the list of locale or language specific function names 1987 $localeFunctions = file($functionNamesFile,FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); 1988 foreach ($localeFunctions as $localeFunction) { 1989 list($localeFunction) = explode('##',$localeFunction); // Strip out comments 1990 if (strpos($localeFunction,'=') !== FALSE) { 1991 list($fName,$lfName) = explode('=',$localeFunction); 1992 $fName = trim($fName); 1993 $lfName = trim($lfName); 1994 if ((isset(self::$_PHPExcelFunctions[$fName])) && ($lfName != '') && ($fName != $lfName)) { 1995 self::$_localeFunctions[$fName] = $lfName; 1996 } 1997 } 1998 } 1999 // Default the TRUE and FALSE constants to the locale names of the TRUE() and FALSE() functions 2000 if (isset(self::$_localeFunctions['TRUE'])) { self::$_localeBoolean['TRUE'] = self::$_localeFunctions['TRUE']; } 2001 if (isset(self::$_localeFunctions['FALSE'])) { self::$_localeBoolean['FALSE'] = self::$_localeFunctions['FALSE']; } 2002 2003 $configFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.str_replace('_',DIRECTORY_SEPARATOR,$locale).DIRECTORY_SEPARATOR.'config'; 2004 if (!file_exists($configFile)) { 2005 $configFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.'config'; 2006 } 2007 if (file_exists($configFile)) { 2008 $localeSettings = file($configFile,FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); 2009 foreach ($localeSettings as $localeSetting) { 2010 list($localeSetting) = explode('##',$localeSetting); // Strip out comments 2011 if (strpos($localeSetting,'=') !== FALSE) { 2012 list($settingName,$settingValue) = explode('=',$localeSetting); 2013 $settingName = strtoupper(trim($settingName)); 2014 switch ($settingName) { 2015 case 'ARGUMENTSEPARATOR' : 2016 self::$_localeArgumentSeparator = trim($settingValue); 2017 break; 2018 } 2019 } 2020 } 2021 } 2022 } 2023 2024 self::$functionReplaceFromExcel = self::$functionReplaceToExcel = 2025 self::$functionReplaceFromLocale = self::$functionReplaceToLocale = NULL; 2026 self::$_localeLanguage = $locale; 2027 return TRUE; 2028 } 2029 return FALSE; 2030 } // function setLocale() 2031 2032 2033 2034 public static function _translateSeparator($fromSeparator,$toSeparator,$formula,&$inBraces) { 2035 $strlen = mb_strlen($formula); 2036 for ($i = 0; $i < $strlen; ++$i) { 2037 $chr = mb_substr($formula,$i,1); 2038 switch ($chr) { 2039 case '{' : $inBraces = TRUE; 2040 break; 2041 case '}' : $inBraces = FALSE; 2042 break; 2043 case $fromSeparator : 2044 if (!$inBraces) { 2045 $formula = mb_substr($formula,0,$i).$toSeparator.mb_substr($formula,$i+1); 2046 } 2047 } 2048 } 2049 return $formula; 2050 } 2051 2052 private static function _translateFormula($from,$to,$formula,$fromSeparator,$toSeparator) { 2053 // Convert any Excel function names to the required language 2054 if (self::$_localeLanguage !== 'en_us') { 2055 $inBraces = FALSE; 2056 // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators 2057 if (strpos($formula,'"') !== FALSE) { 2058 // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded 2059 // the formula 2060 $temp = explode('"',$formula); 2061 $i = FALSE; 2062 foreach($temp as &$value) { 2063 // Only count/replace in alternating array entries 2064 if ($i = !$i) { 2065 $value = preg_replace($from,$to,$value); 2066 $value = self::_translateSeparator($fromSeparator,$toSeparator,$value,$inBraces); 2067 } 2068 } 2069 unset($value); 2070 // Then rebuild the formula string 2071 $formula = implode('"',$temp); 2072 } else { 2073 // If there's no quoted strings, then we do a simple count/replace 2074 $formula = preg_replace($from,$to,$formula); 2075 $formula = self::_translateSeparator($fromSeparator,$toSeparator,$formula,$inBraces); 2076 } 2077 } 2078 2079 return $formula; 2080 } 2081 2082 private static $functionReplaceFromExcel = NULL; 2083 private static $functionReplaceToLocale = NULL; 2084 2085 public function _translateFormulaToLocale($formula) { 2086 if (self::$functionReplaceFromExcel === NULL) { 2087 self::$functionReplaceFromExcel = array(); 2088 foreach(array_keys(self::$_localeFunctions) as $excelFunctionName) { 2089 self::$functionReplaceFromExcel[] = '/(@?[^\w\.])'.preg_quote($excelFunctionName).'([\s]*\()/Ui'; 2090 } 2091 foreach(array_keys(self::$_localeBoolean) as $excelBoolean) { 2092 self::$functionReplaceFromExcel[] = '/(@?[^\w\.])'.preg_quote($excelBoolean).'([^\w\.])/Ui'; 2093 } 2094 2095 } 2096 2097 if (self::$functionReplaceToLocale === NULL) { 2098 self::$functionReplaceToLocale = array(); 2099 foreach(array_values(self::$_localeFunctions) as $localeFunctionName) { 2100 self::$functionReplaceToLocale[] = '$1'.trim($localeFunctionName).'$2'; 2101 } 2102 foreach(array_values(self::$_localeBoolean) as $localeBoolean) { 2103 self::$functionReplaceToLocale[] = '$1'.trim($localeBoolean).'$2'; 2104 } 2105 } 2106 2107 return self::_translateFormula(self::$functionReplaceFromExcel,self::$functionReplaceToLocale,$formula,',',self::$_localeArgumentSeparator); 2108 } // function _translateFormulaToLocale() 2109 2110 2111 private static $functionReplaceFromLocale = NULL; 2112 private static $functionReplaceToExcel = NULL; 2113 2114 public function _translateFormulaToEnglish($formula) { 2115 if (self::$functionReplaceFromLocale === NULL) { 2116 self::$functionReplaceFromLocale = array(); 2117 foreach(array_values(self::$_localeFunctions) as $localeFunctionName) { 2118 self::$functionReplaceFromLocale[] = '/(@?[^\w\.])'.preg_quote($localeFunctionName).'([\s]*\()/Ui'; 2119 } 2120 foreach(array_values(self::$_localeBoolean) as $excelBoolean) { 2121 self::$functionReplaceFromLocale[] = '/(@?[^\w\.])'.preg_quote($excelBoolean).'([^\w\.])/Ui'; 2122 } 2123 } 2124 2125 if (self::$functionReplaceToExcel === NULL) { 2126 self::$functionReplaceToExcel = array(); 2127 foreach(array_keys(self::$_localeFunctions) as $excelFunctionName) { 2128 self::$functionReplaceToExcel[] = '$1'.trim($excelFunctionName).'$2'; 2129 } 2130 foreach(array_keys(self::$_localeBoolean) as $excelBoolean) { 2131 self::$functionReplaceToExcel[] = '$1'.trim($excelBoolean).'$2'; 2132 } 2133 } 2134 2135 return self::_translateFormula(self::$functionReplaceFromLocale,self::$functionReplaceToExcel,$formula,self::$_localeArgumentSeparator,','); 2136 } // function _translateFormulaToEnglish() 2137 2138 2139 public static function _localeFunc($function) { 2140 if (self::$_localeLanguage !== 'en_us') { 2141 $functionName = trim($function,'('); 2142 if (isset(self::$_localeFunctions[$functionName])) { 2143 $brace = ($functionName != $function); 2144 $function = self::$_localeFunctions[$functionName]; 2145 if ($brace) { $function .= '('; } 2146 } 2147 } 2148 return $function; 2149 } 2150 2151 2152 2153 2154 /** 2155 * Wrap string values in quotes 2156 * 2157 * @param mixed $value 2158 * @return mixed 2159 */ 2160 public static function _wrapResult($value) { 2161 if (is_string($value)) { 2162 // Error values cannot be "wrapped" 2163 if (preg_match('/^'.self::CALCULATION_REGEXP_ERROR.'$/i', $value, $match)) { 2164 // Return Excel errors "as is" 2165 return $value; 2166 } 2167 // Return strings wrapped in quotes 2168 return '"'.$value.'"'; 2169 // Convert numeric errors to NaN error 2170 } else if((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) { 2171 return PHPExcel_Calculation_Functions::NaN(); 2172 } 2173 2174 return $value; 2175 } // function _wrapResult() 2176 2177 2178 /** 2179 * Remove quotes used as a wrapper to identify string values 2180 * 2181 * @param mixed $value 2182 * @return mixed 2183 */ 2184 public static function _unwrapResult($value) { 2185 if (is_string($value)) { 2186 if ((isset($value{0})) && ($value{0} == '"') && (substr($value,-1) == '"')) { 2187 return substr($value,1,-1); 2188 } 2189 // Convert numeric errors to NaN error 2190 } else if((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) { 2191 return PHPExcel_Calculation_Functions::NaN(); 2192 } 2193 return $value; 2194 } // function _unwrapResult() 2195 2196 2197 2198 2199 /** 2200 * Calculate cell value (using formula from a cell ID) 2201 * Retained for backward compatibility 2202 * 2203 * @access public 2204 * @param PHPExcel_Cell $pCell Cell to calculate 2205 * @return mixed 2206 * @throws PHPExcel_Calculation_Exception 2207 */ 2208 public function calculate(PHPExcel_Cell $pCell = NULL) { 2209 try { 2210 return $this->calculateCellValue($pCell); 2211 } catch (PHPExcel_Exception $e) { 2212 throw new PHPExcel_Calculation_Exception($e->getMessage()); 2213 } 2214 } // function calculate() 2215 2216 2217 /** 2218 * Calculate the value of a cell formula 2219 * 2220 * @access public 2221 * @param PHPExcel_Cell $pCell Cell to calculate 2222 * @param Boolean $resetLog Flag indicating whether the debug log should be reset or not 2223 * @return mixed 2224 * @throws PHPExcel_Calculation_Exception 2225 */ 2226 public function calculateCellValue(PHPExcel_Cell $pCell = NULL, $resetLog = TRUE) { 2227 if ($pCell === NULL) { 2228 return NULL; 2229 } 2230 2231 $returnArrayAsType = self::$returnArrayAsType; 2232 if ($resetLog) { 2233 // Initialise the logging settings if requested 2234 $this->formulaError = null; 2235 $this->_debugLog->clearLog(); 2236 $this->_cyclicReferenceStack->clear(); 2237 $this->_cyclicFormulaCount = 1; 2238 2239 self::$returnArrayAsType = self::RETURN_ARRAY_AS_ARRAY; 2240 } 2241 2242 // Execute the calculation for the cell formula 2243 try { 2244 $result = self::_unwrapResult($this->_calculateFormulaValue($pCell->getValue(), $pCell->getCoordinate(), $pCell)); 2245 } catch (PHPExcel_Exception $e) { 2246 throw new PHPExcel_Calculation_Exception($e->getMessage()); 2247 } 2248 2249 if ((is_array($result)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) { 2250 self::$returnArrayAsType = $returnArrayAsType; 2251 $testResult = PHPExcel_Calculation_Functions::flattenArray($result); 2252 if (self::$returnArrayAsType == self::RETURN_ARRAY_AS_ERROR) { 2253 return PHPExcel_Calculation_Functions::VALUE(); 2254 } 2255 // If there's only a single cell in the array, then we allow it 2256 if (count($testResult) != 1) { 2257 // If keys are numeric, then it's a matrix result rather than a cell range result, so we permit it 2258 $r = array_keys($result); 2259 $r = array_shift($r); 2260 if (!is_numeric($r)) { return PHPExcel_Calculation_Functions::VALUE(); } 2261 if (is_array($result[$r])) { 2262 $c = array_keys($result[$r]); 2263 $c = array_shift($c); 2264 if (!is_numeric($c)) { 2265 return PHPExcel_Calculation_Functions::VALUE(); 2266 } 2267 } 2268 } 2269 $result = array_shift($testResult); 2270 } 2271 self::$returnArrayAsType = $returnArrayAsType; 2272 2273 2274 if ($result === NULL) { 2275 return 0; 2276 } elseif((is_float($result)) && ((is_nan($result)) || (is_infinite($result)))) { 2277 return PHPExcel_Calculation_Functions::NaN(); 2278 } 2279 return $result; 2280 } // function calculateCellValue( 2281 2282 2283 /** 2284 * Validate and parse a formula string 2285 * 2286 * @param string $formula Formula to parse 2287 * @return array 2288 * @throws PHPExcel_Calculation_Exception 2289 */ 2290 public function parseFormula($formula) { 2291 // Basic validation that this is indeed a formula 2292 // We return an empty array if not 2293 $formula = trim($formula); 2294 if ((!isset($formula{0})) || ($formula{0} != '=')) return array(); 2295 $formula = ltrim(substr($formula,1)); 2296 if (!isset($formula{0})) return array(); 2297 2298 // Parse the formula and return the token stack 2299 return $this->_parseFormula($formula); 2300 } // function parseFormula() 2301 2302 2303 /** 2304 * Calculate the value of a formula 2305 * 2306 * @param string $formula Formula to parse 2307 * @param string $cellID Address of the cell to calculate 2308 * @param PHPExcel_Cell $pCell Cell to calculate 2309 * @return mixed 2310 * @throws PHPExcel_Calculation_Exception 2311 */ 2312 public function calculateFormula($formula, $cellID=NULL, PHPExcel_Cell $pCell = NULL) { 2313 // Initialise the logging settings 2314 $this->formulaError = null; 2315 $this->_debugLog->clearLog(); 2316 $this->_cyclicReferenceStack->clear(); 2317 2318 // Disable calculation cacheing because it only applies to cell calculations, not straight formulae 2319 // But don't actually flush any cache 2320 $resetCache = $this->getCalculationCacheEnabled(); 2321 $this->_calculationCacheEnabled = FALSE; 2322 // Execute the calculation 2323 try { 2324 $result = self::_unwrapResult($this->_calculateFormulaValue($formula, $cellID, $pCell)); 2325 } catch (PHPExcel_Exception $e) { 2326 throw new PHPExcel_Calculation_Exception($e->getMessage()); 2327 } 2328 2329 // Reset calculation cacheing to its previous state 2330 $this->_calculationCacheEnabled = $resetCache; 2331 2332 return $result; 2333 } // function calculateFormula() 2334 2335 2336 public function getValueFromCache($worksheetName, $cellID, &$cellValue) { 2337 // Is calculation cacheing enabled? 2338 // Is the value present in calculation cache? 2339 //echo 'Test cache for ',$worksheetName,'!',$cellID,PHP_EOL; 2340 $this->_debugLog->writeDebugLog('Testing cache value for cell ', $worksheetName, '!', $cellID); 2341 if (($this->_calculationCacheEnabled) && (isset($this->_calculationCache[$worksheetName][$cellID]))) { 2342 //echo 'Retrieve from cache',PHP_EOL; 2343 $this->_debugLog->writeDebugLog('Retrieving value for cell ', $worksheetName, '!', $cellID, ' from cache'); 2344 // Return the cached result 2345 $cellValue = $this->_calculationCache[$worksheetName][$cellID]; 2346 return TRUE; 2347 } 2348 return FALSE; 2349 } 2350 2351 public function saveValueToCache($worksheetName, $cellID, $cellValue) { 2352 if ($this->_calculationCacheEnabled) { 2353 $this->_calculationCache[$worksheetName][$cellID] = $cellValue; 2354 } 2355 } 2356 2357 /** 2358 * Parse a cell formula and calculate its value 2359 * 2360 * @param string $formula The formula to parse and calculate 2361 * @param string $cellID The ID (e.g. A3) of the cell that we are calculating 2362 * @param PHPExcel_Cell $pCell Cell to calculate 2363 * @return mixed 2364 * @throws PHPExcel_Calculation_Exception 2365 */ 2366 public function _calculateFormulaValue($formula, $cellID=null, PHPExcel_Cell $pCell = null) { 2367 $cellValue = ''; 2368 2369 // Basic validation that this is indeed a formula 2370 // We simply return the cell value if not 2371 $formula = trim($formula); 2372 if ($formula{0} != '=') return self::_wrapResult($formula); 2373 $formula = ltrim(substr($formula,1)); 2374 if (!isset($formula{0})) return self::_wrapResult($formula); 2375 2376 $pCellParent = ($pCell !== NULL) ? $pCell->getWorksheet() : NULL; 2377 $wsTitle = ($pCellParent !== NULL) ? $pCellParent->getTitle() : "\x00Wrk"; 2378 2379 if (($cellID !== NULL) && ($this->getValueFromCache($wsTitle, $cellID, $cellValue))) { 2380 return $cellValue; 2381 } 2382 2383 if (($wsTitle{0} !== "\x00") && ($this->_cyclicReferenceStack->onStack($wsTitle.'!'.$cellID))) { 2384 if ($this->cyclicFormulaCount <= 0) { 2385 return $this->_raiseFormulaError('Cyclic Reference in Formula'); 2386 } elseif (($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) && 2387 ($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID)) { 2388 return $cellValue; 2389 } elseif ($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID) { 2390 ++$this->_cyclicFormulaCount; 2391 if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) { 2392 return $cellValue; 2393 } 2394 } elseif ($this->_cyclicFormulaCell == '') { 2395 $this->_cyclicFormulaCell = $wsTitle.'!'.$cellID; 2396 if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) { 2397 return $cellValue; 2398 } 2399 } 2400 } 2401 2402 // Parse the formula onto the token stack and calculate the value 2403 $this->_cyclicReferenceStack->push($wsTitle.'!'.$cellID); 2404 $cellValue = $this->_processTokenStack($this->_parseFormula($formula, $pCell), $cellID, $pCell); 2405 $this->_cyclicReferenceStack->pop(); 2406 2407 // Save to calculation cache 2408 if ($cellID !== NULL) { 2409 $this->saveValueToCache($wsTitle, $cellID, $cellValue); 2410 } 2411 2412 // Return the calculated value 2413 return $cellValue; 2414 } // function _calculateFormulaValue() 2415 2416 2417 /** 2418 * Ensure that paired matrix operands are both matrices and of the same size 2419 * 2420 * @param mixed &$operand1 First matrix operand 2421 * @param mixed &$operand2 Second matrix operand 2422 * @param integer $resize Flag indicating whether the matrices should be resized to match 2423 * and (if so), whether the smaller dimension should grow or the 2424 * larger should shrink. 2425 * 0 = no resize 2426 * 1 = shrink to fit 2427 * 2 = extend to fit 2428 */ 2429 private static function _checkMatrixOperands(&$operand1,&$operand2,$resize = 1) { 2430 // Examine each of the two operands, and turn them into an array if they aren't one already 2431 // Note that this function should only be called if one or both of the operand is already an array 2432 if (!is_array($operand1)) { 2433 list($matrixRows,$matrixColumns) = self::_getMatrixDimensions($operand2); 2434 $operand1 = array_fill(0,$matrixRows,array_fill(0,$matrixColumns,$operand1)); 2435 $resize = 0; 2436 } elseif (!is_array($operand2)) { 2437 list($matrixRows,$matrixColumns) = self::_getMatrixDimensions($operand1); 2438 $operand2 = array_fill(0,$matrixRows,array_fill(0,$matrixColumns,$operand2)); 2439 $resize = 0; 2440 } 2441 2442 list($matrix1Rows,$matrix1Columns) = self::_getMatrixDimensions($operand1); 2443 list($matrix2Rows,$matrix2Columns) = self::_getMatrixDimensions($operand2); 2444 if (($matrix1Rows == $matrix2Columns) && ($matrix2Rows == $matrix1Columns)) { 2445 $resize = 1; 2446 } 2447 2448 if ($resize == 2) { 2449 // Given two matrices of (potentially) unequal size, convert the smaller in each dimension to match the larger 2450 self::_resizeMatricesExtend($operand1,$operand2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns); 2451 } elseif ($resize == 1) { 2452 // Given two matrices of (potentially) unequal size, convert the larger in each dimension to match the smaller 2453 self::_resizeMatricesShrink($operand1,$operand2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns); 2454 } 2455 return array( $matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns); 2456 } // function _checkMatrixOperands() 2457 2458 2459 /** 2460 * Read the dimensions of a matrix, and re-index it with straight numeric keys starting from row 0, column 0 2461 * 2462 * @param mixed &$matrix matrix operand 2463 * @return array An array comprising the number of rows, and number of columns 2464 */ 2465 public static function _getMatrixDimensions(&$matrix) { 2466 $matrixRows = count($matrix); 2467 $matrixColumns = 0; 2468 foreach($matrix as $rowKey => $rowValue) { 2469 $matrixColumns = max(count($rowValue),$matrixColumns); 2470 if (!is_array($rowValue)) { 2471 $matrix[$rowKey] = array($rowValue); 2472 } else { 2473 $matrix[$rowKey] = array_values($rowValue); 2474 } 2475 } 2476 $matrix = array_values($matrix); 2477 return array($matrixRows,$matrixColumns); 2478 } // function _getMatrixDimensions() 2479 2480 2481 /** 2482 * Ensure that paired matrix operands are both matrices of the same size 2483 * 2484 * @param mixed &$matrix1 First matrix operand 2485 * @param mixed &$matrix2 Second matrix operand 2486 * @param integer $matrix1Rows Row size of first matrix operand 2487 * @param integer $matrix1Columns Column size of first matrix operand 2488 * @param integer $matrix2Rows Row size of second matrix operand 2489 * @param integer $matrix2Columns Column size of second matrix operand 2490 */ 2491 private static function _resizeMatricesShrink(&$matrix1,&$matrix2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns) { 2492 if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) { 2493 if ($matrix2Rows < $matrix1Rows) { 2494 for ($i = $matrix2Rows; $i < $matrix1Rows; ++$i) { 2495 unset($matrix1[$i]); 2496 } 2497 } 2498 if ($matrix2Columns < $matrix1Columns) { 2499 for ($i = 0; $i < $matrix1Rows; ++$i) { 2500 for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) { 2501 unset($matrix1[$i][$j]); 2502 } 2503 } 2504 } 2505 } 2506 2507 if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) { 2508 if ($matrix1Rows < $matrix2Rows) { 2509 for ($i = $matrix1Rows; $i < $matrix2Rows; ++$i) { 2510 unset($matrix2[$i]); 2511 } 2512 } 2513 if ($matrix1Columns < $matrix2Columns) { 2514 for ($i = 0; $i < $matrix2Rows; ++$i) { 2515 for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) { 2516 unset($matrix2[$i][$j]); 2517 } 2518 } 2519 } 2520 } 2521 } // function _resizeMatricesShrink() 2522 2523 2524 /** 2525 * Ensure that paired matrix operands are both matrices of the same size 2526 * 2527 * @param mixed &$matrix1 First matrix operand 2528 * @param mixed &$matrix2 Second matrix operand 2529 * @param integer $matrix1Rows Row size of first matrix operand 2530 * @param integer $matrix1Columns Column size of first matrix operand 2531 * @param integer $matrix2Rows Row size of second matrix operand 2532 * @param integer $matrix2Columns Column size of second matrix operand 2533 */ 2534 private static function _resizeMatricesExtend(&$matrix1,&$matrix2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns) { 2535 if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) { 2536 if ($matrix2Columns < $matrix1Columns) { 2537 for ($i = 0; $i < $matrix2Rows; ++$i) { 2538 $x = $matrix2[$i][$matrix2Columns-1]; 2539 for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) { 2540 $matrix2[$i][$j] = $x; 2541 } 2542 } 2543 } 2544 if ($matrix2Rows < $matrix1Rows) { 2545 $x = $matrix2[$matrix2Rows-1]; 2546 for ($i = 0; $i < $matrix1Rows; ++$i) { 2547 $matrix2[$i] = $x; 2548 } 2549 } 2550 } 2551 2552 if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) { 2553 if ($matrix1Columns < $matrix2Columns) { 2554 for ($i = 0; $i < $matrix1Rows; ++$i) { 2555 $x = $matrix1[$i][$matrix1Columns-1]; 2556 for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) { 2557 $matrix1[$i][$j] = $x; 2558 } 2559 } 2560 } 2561 if ($matrix1Rows < $matrix2Rows) { 2562 $x = $matrix1[$matrix1Rows-1]; 2563 for ($i = 0; $i < $matrix2Rows; ++$i) { 2564 $matrix1[$i] = $x; 2565 } 2566 } 2567 } 2568 } // function _resizeMatricesExtend() 2569 2570 2571 /** 2572 * Format details of an operand for display in the log (based on operand type) 2573 * 2574 * @param mixed $value First matrix operand 2575 * @return mixed 2576 */ 2577 private function _showValue($value) { 2578 if ($this->_debugLog->getWriteDebugLog()) { 2579 $testArray = PHPExcel_Calculation_Functions::flattenArray($value); 2580 if (count($testArray) == 1) { 2581 $value = array_pop($testArray); 2582 } 2583 2584 if (is_array($value)) { 2585 $returnMatrix = array(); 2586 $pad = $rpad = ', '; 2587 foreach($value as $row) { 2588 if (is_array($row)) { 2589 $returnMatrix[] = implode($pad,array_map(array($this,'_showValue'),$row)); 2590 $rpad = '; '; 2591 } else { 2592 $returnMatrix[] = $this->_showValue($row); 2593 } 2594 } 2595 return '{ '.implode($rpad,$returnMatrix).' }'; 2596 } elseif(is_string($value) && (trim($value,'"') == $value)) { 2597 return '"'.$value.'"'; 2598 } elseif(is_bool($value)) { 2599 return ($value) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE']; 2600 } 2601 } 2602 return PHPExcel_Calculation_Functions::flattenSingleValue($value); 2603 } // function _showValue() 2604 2605 2606 /** 2607 * Format type and details of an operand for display in the log (based on operand type) 2608 * 2609 * @param mixed $value First matrix operand 2610 * @return mixed 2611 */ 2612 private function _showTypeDetails($value) { 2613 if ($this->_debugLog->getWriteDebugLog()) { 2614 $testArray = PHPExcel_Calculation_Functions::flattenArray($value); 2615 if (count($testArray) == 1) { 2616 $value = array_pop($testArray); 2617 } 2618 2619 if ($value === NULL) { 2620 return 'a NULL value'; 2621 } elseif (is_float($value)) { 2622 $typeString = 'a floating point number'; 2623 } elseif(is_int($value)) { 2624 $typeString = 'an integer number'; 2625 } elseif(is_bool($value)) { 2626 $typeString = 'a boolean'; 2627 } elseif(is_array($value)) { 2628 $typeString = 'a matrix'; 2629 } else { 2630 if ($value == '') { 2631 return 'an empty string'; 2632 } elseif ($value{0} == '#') { 2633 return 'a '.$value.' error'; 2634 } else { 2635 $typeString = 'a string'; 2636 } 2637 } 2638 return $typeString.' with a value of '.$this->_showValue($value); 2639 } 2640 } // function _showTypeDetails() 2641 2642 2643 private static function _convertMatrixReferences($formula) { 2644 static $matrixReplaceFrom = array('{',';','}'); 2645 static $matrixReplaceTo = array('MKMATRIX(MKMATRIX(','),MKMATRIX(','))'); 2646 2647 // Convert any Excel matrix references to the MKMATRIX() function 2648 if (strpos($formula,'{') !== FALSE) { 2649 // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators 2650 if (strpos($formula,'"') !== FALSE) { 2651 // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded 2652 // the formula 2653 $temp = explode('"',$formula); 2654 // Open and Closed counts used for trapping mismatched braces in the formula 2655 $openCount = $closeCount = 0; 2656 $i = FALSE; 2657 foreach($temp as &$value) { 2658 // Only count/replace in alternating array entries 2659 if ($i = !$i) { 2660 $openCount += substr_count($value,'{'); 2661 $closeCount += substr_count($value,'}'); 2662 $value = str_replace($matrixReplaceFrom,$matrixReplaceTo,$value); 2663 } 2664 } 2665 unset($value); 2666 // Then rebuild the formula string 2667 $formula = implode('"',$temp); 2668 } else { 2669 // If there's no quoted strings, then we do a simple count/replace 2670 $openCount = substr_count($formula,'{'); 2671 $closeCount = substr_count($formula,'}'); 2672 $formula = str_replace($matrixReplaceFrom,$matrixReplaceTo,$formula); 2673 } 2674 // Trap for mismatched braces and trigger an appropriate error 2675 if ($openCount < $closeCount) { 2676 if ($openCount > 0) { 2677 return $this->_raiseFormulaError("Formula Error: Mismatched matrix braces '}'"); 2678 } else { 2679 return $this->_raiseFormulaError("Formula Error: Unexpected '}' encountered"); 2680 } 2681 } elseif ($openCount > $closeCount) { 2682 if ($closeCount > 0) { 2683 return $this->_raiseFormulaError("Formula Error: Mismatched matrix braces '{'"); 2684 } else { 2685 return $this->_raiseFormulaError("Formula Error: Unexpected '{' encountered"); 2686 } 2687 } 2688 } 2689 2690 return $formula; 2691 } // function _convertMatrixReferences() 2692 2693 2694 private static function _mkMatrix() { 2695 return func_get_args(); 2696 } // function _mkMatrix() 2697 2698 2699 // Binary Operators 2700 // These operators always work on two values 2701 // Array key is the operator, the value indicates whether this is a left or right associative operator 2702 private static $_operatorAssociativity = array( 2703 '^' => 0, // Exponentiation 2704 '*' => 0, '/' => 0, // Multiplication and Division 2705 '+' => 0, '-' => 0, // Addition and Subtraction 2706 '&' => 0, // Concatenation 2707 '|' => 0, ':' => 0, // Intersect and Range 2708 '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison 2709 ); 2710 2711 // Comparison (Boolean) Operators 2712 // These operators work on two values, but always return a boolean result 2713 private static $_comparisonOperators = array('>' => TRUE, '<' => TRUE, '=' => TRUE, '>=' => TRUE, '<=' => TRUE, '<>' => TRUE); 2714 2715 // Operator Precedence 2716 // This list includes all valid operators, whether binary (including boolean) or unary (such as %) 2717 // Array key is the operator, the value is its precedence 2718 private static $_operatorPrecedence = array( 2719 ':' => 8, // Range 2720 '|' => 7, // Intersect 2721 '~' => 6, // Negation 2722 '%' => 5, // Percentage 2723 '^' => 4, // Exponentiation 2724 '*' => 3, '/' => 3, // Multiplication and Division 2725 '+' => 2, '-' => 2, // Addition and Subtraction 2726 '&' => 1, // Concatenation 2727 '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison 2728 ); 2729 2730 // Convert infix to postfix notation 2731 private function _parseFormula($formula, PHPExcel_Cell $pCell = NULL) { 2732 if (($formula = self::_convertMatrixReferences(trim($formula))) === FALSE) { 2733 return FALSE; 2734 } 2735 2736 // If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent worksheet), 2737 // so we store the parent worksheet so that we can re-attach it when necessary 2738 $pCellParent = ($pCell !== NULL) ? $pCell->getWorksheet() : NULL; 2739 2740 $regexpMatchString = '/^('.self::CALCULATION_REGEXP_FUNCTION. 2741 '|'.self::CALCULATION_REGEXP_CELLREF. 2742 '|'.self::CALCULATION_REGEXP_NUMBER. 2743 '|'.self::CALCULATION_REGEXP_STRING. 2744 '|'.self::CALCULATION_REGEXP_OPENBRACE. 2745 '|'.self::CALCULATION_REGEXP_NAMEDRANGE. 2746 '|'.self::CALCULATION_REGEXP_ERROR. 2747 ')/si'; 2748 2749 // Start with initialisation 2750 $index = 0; 2751 $stack = new PHPExcel_Calculation_Token_Stack; 2752 $output = array(); 2753 $expectingOperator = FALSE; // We use this test in syntax-checking the expression to determine when a 2754 // - is a negation or + is a positive operator rather than an operation 2755 $expectingOperand = FALSE; // We use this test in syntax-checking the expression to determine whether an operand 2756 // should be null in a function call 2757 // The guts of the lexical parser 2758 // Loop through the formula extracting each operator and operand in turn 2759 while(TRUE) { 2760 //echo 'Assessing Expression '.substr($formula, $index),PHP_EOL; 2761 $opCharacter = $formula{$index}; // Get the first character of the value at the current index position 2762 //echo 'Initial character of expression block is '.$opCharacter,PHP_EOL; 2763 if ((isset(self::$_comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset(self::$_comparisonOperators[$formula{$index+1}]))) { 2764 $opCharacter .= $formula{++$index}; 2765 //echo 'Initial character of expression block is comparison operator '.$opCharacter.PHP_EOL; 2766 } 2767 2768 // Find out if we're currently at the beginning of a number, variable, cell reference, function, parenthesis or operand 2769 $isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match); 2770 //echo '$isOperandOrFunction is '.(($isOperandOrFunction) ? 'True' : 'False').PHP_EOL; 2771 //var_dump($match); 2772 2773 if ($opCharacter == '-' && !$expectingOperator) { // Is it a negation instead of a minus? 2774 //echo 'Element is a Negation operator',PHP_EOL; 2775 $stack->push('Unary Operator','~'); // Put a negation on the stack 2776 ++$index; // and drop the negation symbol 2777 } elseif ($opCharacter == '%' && $expectingOperator) { 2778 //echo 'Element is a Percentage operator',PHP_EOL; 2779 $stack->push('Unary Operator','%'); // Put a percentage on the stack 2780 ++$index; 2781 } elseif ($opCharacter == '+' && !$expectingOperator) { // Positive (unary plus rather than binary operator plus) can be discarded? 2782 //echo 'Element is a Positive number, not Plus operator',PHP_EOL; 2783 ++$index; // Drop the redundant plus symbol 2784 } elseif ((($opCharacter == '~') || ($opCharacter == '|')) && (!$isOperandOrFunction)) { // We have to explicitly deny a tilde or pipe, because they are legal 2785 return $this->_raiseFormulaError("Formula Error: Illegal character '~'"); // on the stack but not in the input expression 2786 2787 } elseif ((isset(self::$_operators[$opCharacter]) or $isOperandOrFunction) && $expectingOperator) { // Are we putting an operator on the stack? 2788 //echo 'Element with value '.$opCharacter.' is an Operator',PHP_EOL; 2789 while($stack->count() > 0 && 2790 ($o2 = $stack->last()) && 2791 isset(self::$_operators[$o2['value']]) && 2792 @(self::$_operatorAssociativity[$opCharacter] ? self::$_operatorPrecedence[$opCharacter] < self::$_operatorPrecedence[$o2['value']] : self::$_operatorPrecedence[$opCharacter] <= self::$_operatorPrecedence[$o2['value']])) { 2793 $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output 2794 } 2795 $stack->push('Binary Operator',$opCharacter); // Finally put our current operator onto the stack 2796 ++$index; 2797 $expectingOperator = FALSE; 2798 2799 } elseif ($opCharacter == ')' && $expectingOperator) { // Are we expecting to close a parenthesis? 2800 //echo 'Element is a Closing bracket',PHP_EOL; 2801 $expectingOperand = FALSE; 2802 while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last ( 2803 if ($o2 === NULL) return $this->_raiseFormulaError('Formula Error: Unexpected closing brace ")"'); 2804 else $output[] = $o2; 2805 } 2806 $d = $stack->last(2); 2807 if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches)) { // Did this parenthesis just close a function? 2808 $functionName = $matches[1]; // Get the function name 2809 //echo 'Closed Function is '.$functionName,PHP_EOL; 2810 $d = $stack->pop(); 2811 $argumentCount = $d['value']; // See how many arguments there were (argument count is the next value stored on the stack) 2812 //if ($argumentCount == 0) { 2813 // echo 'With no arguments',PHP_EOL; 2814 //} elseif ($argumentCount == 1) { 2815 // echo 'With 1 argument',PHP_EOL; 2816 //} else { 2817 // echo 'With '.$argumentCount.' arguments',PHP_EOL; 2818 //} 2819 $output[] = $d; // Dump the argument count on the output 2820 $output[] = $stack->pop(); // Pop the function and push onto the output 2821 if (isset(self::$_controlFunctions[$functionName])) { 2822 //echo 'Built-in function '.$functionName,PHP_EOL; 2823 $expectedArgumentCount = self::$_controlFunctions[$functionName]['argumentCount']; 2824 $functionCall = self::$_controlFunctions[$functionName]['functionCall']; 2825 } elseif (isset(self::$_PHPExcelFunctions[$functionName])) { 2826 //echo 'PHPExcel function '.$functionName,PHP_EOL; 2827 $expectedArgumentCount = self::$_PHPExcelFunctions[$functionName]['argumentCount']; 2828 $functionCall = self::$_PHPExcelFunctions[$functionName]['functionCall']; 2829 } else { // did we somehow push a non-function on the stack? this should never happen 2830 return $this->_raiseFormulaError("Formula Error: Internal error, non-function on stack"); 2831 } 2832 // Check the argument count 2833 $argumentCountError = FALSE; 2834 if (is_numeric($expectedArgumentCount)) { 2835 if ($expectedArgumentCount < 0) { 2836 //echo '$expectedArgumentCount is between 0 and '.abs($expectedArgumentCount),PHP_EOL; 2837 if ($argumentCount > abs($expectedArgumentCount)) { 2838 $argumentCountError = TRUE; 2839 $expectedArgumentCountString = 'no more than '.abs($expectedArgumentCount); 2840 } 2841 } else { 2842 //echo '$expectedArgumentCount is numeric '.$expectedArgumentCount,PHP_EOL; 2843 if ($argumentCount != $expectedArgumentCount) { 2844 $argumentCountError = TRUE; 2845 $expectedArgumentCountString = $expectedArgumentCount; 2846 } 2847 } 2848 } elseif ($expectedArgumentCount != '*') { 2849 $isOperandOrFunction = preg_match('/(\d*)([-+,])(\d*)/',$expectedArgumentCount,$argMatch); 2850 //print_r($argMatch); 2851 //echo PHP_EOL; 2852 switch ($argMatch[2]) { 2853 case '+' : 2854 if ($argumentCount < $argMatch[1]) { 2855 $argumentCountError = TRUE; 2856 $expectedArgumentCountString = $argMatch[1].' or more '; 2857 } 2858 break; 2859 case '-' : 2860 if (($argumentCount < $argMatch[1]) || ($argumentCount > $argMatch[3])) { 2861 $argumentCountError = TRUE; 2862 $expectedArgumentCountString = 'between '.$argMatch[1].' and '.$argMatch[3]; 2863 } 2864 break; 2865 case ',' : 2866 if (($argumentCount != $argMatch[1]) && ($argumentCount != $argMatch[3])) { 2867 $argumentCountError = TRUE; 2868 $expectedArgumentCountString = 'either '.$argMatch[1].' or '.$argMatch[3]; 2869 } 2870 break; 2871 } 2872 } 2873 if ($argumentCountError) { 2874 return $this->_raiseFormulaError("Formula Error: Wrong number of arguments for $functionName() function: $argumentCount given, ".$expectedArgumentCountString." expected"); 2875 } 2876 } 2877 ++$index; 2878 2879 } elseif ($opCharacter == ',') { // Is this the separator for function arguments? 2880 //echo 'Element is a Function argument separator',PHP_EOL; 2881 while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last ( 2882 if ($o2 === NULL) return $this->_raiseFormulaError("Formula Error: Unexpected ,"); 2883 else $output[] = $o2; // pop the argument expression stuff and push onto the output 2884 } 2885 // If we've a comma when we're expecting an operand, then what we actually have is a null operand; 2886 // so push a null onto the stack 2887 if (($expectingOperand) || (!$expectingOperator)) { 2888 $output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => NULL); 2889 } 2890 // make sure there was a function 2891 $d = $stack->last(2); 2892 if (!preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches)) 2893 return $this->_raiseFormulaError("Formula Error: Unexpected ,"); 2894 $d = $stack->pop(); 2895 $stack->push($d['type'],++$d['value'],$d['reference']); // increment the argument count 2896 $stack->push('Brace', '('); // put the ( back on, we'll need to pop back to it again 2897 $expectingOperator = FALSE; 2898 $expectingOperand = TRUE; 2899 ++$index; 2900 2901 } elseif ($opCharacter == '(' && !$expectingOperator) { 2902 // echo 'Element is an Opening Bracket<br />'; 2903 $stack->push('Brace', '('); 2904 ++$index; 2905 2906 } elseif ($isOperandOrFunction && !$expectingOperator) { // do we now have a function/variable/number? 2907 $expectingOperator = TRUE; 2908 $expectingOperand = FALSE; 2909 $val = $match[1]; 2910 $length = strlen($val); 2911 // echo 'Element with value '.$val.' is an Operand, Variable, Constant, String, Number, Cell Reference or Function<br />'; 2912 2913 if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $val, $matches)) { 2914 $val = preg_replace('/\s/','',$val); 2915 // echo 'Element '.$val.' is a Function<br />'; 2916 if (isset(self::$_PHPExcelFunctions[strtoupper($matches[1])]) || isset(self::$_controlFunctions[strtoupper($matches[1])])) { // it's a function 2917 $stack->push('Function', strtoupper($val)); 2918 $ax = preg_match('/^\s*(\s*\))/i', substr($formula, $index+$length), $amatch); 2919 if ($ax) { 2920 $stack->push('Operand Count for Function '.strtoupper($val).')', 0); 2921 $expectingOperator = TRUE; 2922 } else { 2923 $stack->push('Operand Count for Function '.strtoupper($val).')', 1); 2924 $expectingOperator = FALSE; 2925 } 2926 $stack->push('Brace', '('); 2927 } else { // it's a var w/ implicit multiplication 2928 $output[] = array('type' => 'Value', 'value' => $matches[1], 'reference' => NULL); 2929 } 2930 } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $val, $matches)) { 2931 // echo 'Element '.$val.' is a Cell reference<br />'; 2932 // Watch for this case-change when modifying to allow cell references in different worksheets... 2933 // Should only be applied to the actual cell column, not the worksheet name 2934 2935 // If the last entry on the stack was a : operator, then we have a cell range reference 2936 $testPrevOp = $stack->last(1); 2937 if ($testPrevOp['value'] == ':') { 2938 // If we have a worksheet reference, then we're playing with a 3D reference 2939 if ($matches[2] == '') { 2940 // Otherwise, we 'inherit' the worksheet reference from the start cell reference 2941 // The start of the cell range reference should be the last entry in $output 2942 $startCellRef = $output[count($output)-1]['value']; 2943 preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $startCellRef, $startMatches); 2944 if ($startMatches[2] > '') { 2945 $val = $startMatches[2].'!'.$val; 2946 } 2947 } else { 2948 return $this->_raiseFormulaError("3D Range references are not yet supported"); 2949 } 2950 } 2951 2952 $output[] = array('type' => 'Cell Reference', 'value' => $val, 'reference' => $val); 2953 // $expectingOperator = FALSE; 2954 } else { // it's a variable, constant, string, number or boolean 2955 // echo 'Element is a Variable, Constant, String, Number or Boolean<br />'; 2956 // If the last entry on the stack was a : operator, then we may have a row or column range reference 2957 $testPrevOp = $stack->last(1); 2958 if ($testPrevOp['value'] == ':') { 2959 $startRowColRef = $output[count($output)-1]['value']; 2960 $rangeWS1 = ''; 2961 if (strpos('!',$startRowColRef) !== FALSE) { 2962 list($rangeWS1,$startRowColRef) = explode('!',$startRowColRef); 2963 } 2964 if ($rangeWS1 != '') $rangeWS1 .= '!'; 2965 $rangeWS2 = $rangeWS1; 2966 if (strpos('!',$val) !== FALSE) { 2967 list($rangeWS2,$val) = explode('!',$val); 2968 } 2969 if ($rangeWS2 != '') $rangeWS2 .= '!'; 2970 if ((is_integer($startRowColRef)) && (ctype_digit($val)) && 2971 ($startRowColRef <= 1048576) && ($val <= 1048576)) { 2972 // Row range 2973 $endRowColRef = ($pCellParent !== NULL) ? $pCellParent->getHighestColumn() : 'XFD'; // Max 16,384 columns for Excel2007 2974 $output[count($output)-1]['value'] = $rangeWS1.'A'.$startRowColRef; 2975 $val = $rangeWS2.$endRowColRef.$val; 2976 } elseif ((ctype_alpha($startRowColRef)) && (ctype_alpha($val)) && 2977 (strlen($startRowColRef) <= 3) && (strlen($val) <= 3)) { 2978 // Column range 2979 $endRowColRef = ($pCellParent !== NULL) ? $pCellParent->getHighestRow() : 1048576; // Max 1,048,576 rows for Excel2007 2980 $output[count($output)-1]['value'] = $rangeWS1.strtoupper($startRowColRef).'1'; 2981 $val = $rangeWS2.$val.$endRowColRef; 2982 } 2983 } 2984 2985 $localeConstant = FALSE; 2986 if ($opCharacter == '"') { 2987 // echo 'Element is a String<br />'; 2988 // UnEscape any quotes within the string 2989 $val = self::_wrapResult(str_replace('""','"',self::_unwrapResult($val))); 2990 } elseif (is_numeric($val)) { 2991 // echo 'Element is a Number<br />'; 2992 if ((strpos($val,'.') !== FALSE) || (stripos($val,'e') !== FALSE) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) { 2993 // echo 'Casting '.$val.' to float<br />'; 2994 $val = (float) $val; 2995 } else { 2996 // echo 'Casting '.$val.' to integer<br />'; 2997 $val = (integer) $val; 2998 } 2999 } elseif (isset(self::$_ExcelConstants[trim(strtoupper($val))])) { 3000 $excelConstant = trim(strtoupper($val)); 3001 // echo 'Element '.$excelConstant.' is an Excel Constant<br />'; 3002 $val = self::$_ExcelConstants[$excelConstant]; 3003 } elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$_localeBoolean)) !== FALSE) { 3004 // echo 'Element '.$localeConstant.' is an Excel Constant<br />'; 3005 $val = self::$_ExcelConstants[$localeConstant]; 3006 } 3007 $details = array('type' => 'Value', 'value' => $val, 'reference' => NULL); 3008 if ($localeConstant) { $details['localeValue'] = $localeConstant; } 3009 $output[] = $details; 3010 } 3011 $index += $length; 3012 3013 } elseif ($opCharacter == '$') { // absolute row or column range 3014 ++$index; 3015 } elseif ($opCharacter == ')') { // miscellaneous error checking 3016 if ($expectingOperand) { 3017 $output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => NULL); 3018 $expectingOperand = FALSE; 3019 $expectingOperator = TRUE; 3020 } else { 3021 return $this->_raiseFormulaError("Formula Error: Unexpected ')'"); 3022 } 3023 } elseif (isset(self::$_operators[$opCharacter]) && !$expectingOperator) { 3024 return $this->_raiseFormulaError("Formula Error: Unexpected operator '$opCharacter'"); 3025 } else { // I don't even want to know what you did to get here 3026 return $this->_raiseFormulaError("Formula Error: An unexpected error occured"); 3027 } 3028 // Test for end of formula string 3029 if ($index == strlen($formula)) { 3030 // Did we end with an operator?. 3031 // Only valid for the % unary operator 3032 if ((isset(self::$_operators[$opCharacter])) && ($opCharacter != '%')) { 3033 return $this->_raiseFormulaError("Formula Error: Operator '$opCharacter' has no operands"); 3034 } else { 3035 break; 3036 } 3037 } 3038 // Ignore white space 3039 while (($formula{$index} == "\n") || ($formula{$index} == "\r")) { 3040 ++$index; 3041 } 3042 if ($formula{$index} == ' ') { 3043 while ($formula{$index} == ' ') { 3044 ++$index; 3045 } 3046 // If we're expecting an operator, but only have a space between the previous and next operands (and both are 3047 // Cell References) then we have an INTERSECTION operator 3048 // echo 'Possible Intersect Operator<br />'; 3049 if (($expectingOperator) && (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'.*/Ui', substr($formula, $index), $match)) && 3050 ($output[count($output)-1]['type'] == 'Cell Reference')) { 3051 // echo 'Element is an Intersect Operator<br />'; 3052 while($stack->count() > 0 && 3053 ($o2 = $stack->last()) && 3054 isset(self::$_operators[$o2['value']]) && 3055 @(self::$_operatorAssociativity[$opCharacter] ? self::$_operatorPrecedence[$opCharacter] < self::$_operatorPrecedence[$o2['value']] : self::$_operatorPrecedence[$opCharacter] <= self::$_operatorPrecedence[$o2['value']])) { 3056 $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output 3057 } 3058 $stack->push('Binary Operator','|'); // Put an Intersect Operator on the stack 3059 $expectingOperator = FALSE; 3060 } 3061 } 3062 } 3063 3064 while (($op = $stack->pop()) !== NULL) { // pop everything off the stack and push onto output 3065 if ((is_array($op) && $op['value'] == '(') || ($op === '(')) 3066 return $this->_raiseFormulaError("Formula Error: Expecting ')'"); // if there are any opening braces on the stack, then braces were unbalanced 3067 $output[] = $op; 3068 } 3069 return $output; 3070 } // function _parseFormula() 3071 3072 3073 private static function _dataTestReference(&$operandData) 3074 { 3075 $operand = $operandData['value']; 3076 if (($operandData['reference'] === NULL) && (is_array($operand))) { 3077 $rKeys = array_keys($operand); 3078 $rowKey = array_shift($rKeys); 3079 $cKeys = array_keys(array_keys($operand[$rowKey])); 3080 $colKey = array_shift($cKeys); 3081 if (ctype_upper($colKey)) { 3082 $operandData['reference'] = $colKey.$rowKey; 3083 } 3084 } 3085 return $operand; 3086 } 3087 3088 // evaluate postfix notation 3089 private function _processTokenStack($tokens, $cellID = NULL, PHPExcel_Cell $pCell = NULL) { 3090 if ($tokens == FALSE) return FALSE; 3091 3092 // If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent cell collection), 3093 // so we store the parent cell collection so that we can re-attach it when necessary 3094 $pCellWorksheet = ($pCell !== NULL) ? $pCell->getWorksheet() : NULL; 3095 $pCellParent = ($pCell !== NULL) ? $pCell->getParent() : null; 3096 $stack = new PHPExcel_Calculation_Token_Stack; 3097 3098 // Loop through each token in turn 3099 foreach ($tokens as $tokenData) { 3100 // print_r($tokenData); 3101 // echo '<br />'; 3102 $token = $tokenData['value']; 3103 // echo '<b>Token is '.$token.'</b><br />'; 3104 // 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 3105 if (isset(self::$_binaryOperators[$token])) { 3106 // echo 'Token is a binary operator<br />'; 3107 // We must have two operands, error if we don't 3108 if (($operand2Data = $stack->pop()) === NULL) return $this->_raiseFormulaError('Internal error - Operand value missing from stack'); 3109 if (($operand1Data = $stack->pop()) === NULL) return $this->_raiseFormulaError('Internal error - Operand value missing from stack'); 3110 3111 $operand1 = self::_dataTestReference($operand1Data); 3112 $operand2 = self::_dataTestReference($operand2Data); 3113 3114 // Log what we're doing 3115 if ($token == ':') { 3116 $this->_debugLog->writeDebugLog('Evaluating Range ', $this->_showValue($operand1Data['reference']), ' ', $token, ' ', $this->_showValue($operand2Data['reference'])); 3117 } else { 3118 $this->_debugLog->writeDebugLog('Evaluating ', $this->_showValue($operand1), ' ', $token, ' ', $this->_showValue($operand2)); 3119 } 3120 3121 // Process the operation in the appropriate manner 3122 switch ($token) { 3123 // Comparison (Boolean) Operators 3124 case '>' : // Greater than 3125 case '<' : // Less than 3126 case '>=' : // Greater than or Equal to 3127 case '<=' : // Less than or Equal to 3128 case '=' : // Equality 3129 case '<>' : // Inequality 3130 $this->_executeBinaryComparisonOperation($cellID,$operand1,$operand2,$token,$stack); 3131 break; 3132 // Binary Operators 3133 case ':' : // Range 3134 $sheet1 = $sheet2 = ''; 3135 if (strpos($operand1Data['reference'],'!') !== FALSE) { 3136 list($sheet1,$operand1Data['reference']) = explode('!',$operand1Data['reference']); 3137 } else { 3138 $sheet1 = ($pCellParent !== NULL) ? $pCellWorksheet->getTitle() : ''; 3139 } 3140 if (strpos($operand2Data['reference'],'!') !== FALSE) { 3141 list($sheet2,$operand2Data['reference']) = explode('!',$operand2Data['reference']); 3142 } else { 3143 $sheet2 = $sheet1; 3144 } 3145 if ($sheet1 == $sheet2) { 3146 if ($operand1Data['reference'] === NULL) { 3147 if ((trim($operand1Data['value']) != '') && (is_numeric($operand1Data['value']))) { 3148 $operand1Data['reference'] = $pCell->getColumn().$operand1Data['value']; 3149 } elseif (trim($operand1Data['reference']) == '') { 3150 $operand1Data['reference'] = $pCell->getCoordinate(); 3151 } else { 3152 $operand1Data['reference'] = $operand1Data['value'].$pCell->getRow(); 3153 } 3154 } 3155 if ($operand2Data['reference'] === NULL) { 3156 if ((trim($operand2Data['value']) != '') && (is_numeric($operand2Data['value']))) { 3157 $operand2Data['reference'] = $pCell->getColumn().$operand2Data['value']; 3158 } elseif (trim($operand2Data['reference']) == '') { 3159 $operand2Data['reference'] = $pCell->getCoordinate(); 3160 } else { 3161 $operand2Data['reference'] = $operand2Data['value'].$pCell->getRow(); 3162 } 3163 } 3164 3165 $oData = array_merge(explode(':',$operand1Data['reference']),explode(':',$operand2Data['reference'])); 3166 $oCol = $oRow = array(); 3167 foreach($oData as $oDatum) { 3168 $oCR = PHPExcel_Cell::coordinateFromString($oDatum); 3169 $oCol[] = PHPExcel_Cell::columnIndexFromString($oCR[0]) - 1; 3170 $oRow[] = $oCR[1]; 3171 } 3172 $cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow); 3173 if ($pCellParent !== NULL) { 3174 $cellValue = $this->extractCellRange($cellRef, $this->_workbook->getSheetByName($sheet1), FALSE); 3175 } else { 3176 return $this->_raiseFormulaError('Unable to access Cell Reference'); 3177 } 3178 $stack->push('Cell Reference',$cellValue,$cellRef); 3179 } else { 3180 $stack->push('Error',PHPExcel_Calculation_Functions::REF(),NULL); 3181 } 3182 3183 break; 3184 case '+' : // Addition 3185 $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'plusEquals',$stack); 3186 break; 3187 case '-' : // Subtraction 3188 $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'minusEquals',$stack); 3189 break; 3190 case '*' : // Multiplication 3191 $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'arrayTimesEquals',$stack); 3192 break; 3193 case '/' : // Division 3194 $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'arrayRightDivide',$stack); 3195 break; 3196 case '^' : // Exponential 3197 $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'power',$stack); 3198 break; 3199 case '&' : // Concatenation 3200 // If either of the operands is a matrix, we need to treat them both as matrices 3201 // (converting the other operand to a matrix if need be); then perform the required 3202 // matrix operation 3203 if (is_bool($operand1)) { 3204 $operand1 = ($operand1) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE']; 3205 } 3206 if (is_bool($operand2)) { 3207 $operand2 = ($operand2) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE']; 3208 } 3209 if ((is_array($operand1)) || (is_array($operand2))) { 3210 // Ensure that both operands are arrays/matrices 3211 self::_checkMatrixOperands($operand1,$operand2,2); 3212 try { 3213 // Convert operand 1 from a PHP array to a matrix 3214 $matrix = new PHPExcel_Shared_JAMA_Matrix($operand1); 3215 // Perform the required operation against the operand 1 matrix, passing in operand 2 3216 $matrixResult = $matrix->concat($operand2); 3217 $result = $matrixResult->getArray(); 3218 } catch (PHPExcel_Exception $ex) { 3219 $this->_debugLog->writeDebugLog('JAMA Matrix Exception: ', $ex->getMessage()); 3220 $result = '#VALUE!'; 3221 } 3222 } else { 3223 $result = '"'.str_replace('""','"',self::_unwrapResult($operand1,'"').self::_unwrapResult($operand2,'"')).'"'; 3224 } 3225 $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($result)); 3226 $stack->push('Value',$result); 3227 break; 3228 case '|' : // Intersect 3229 $rowIntersect = array_intersect_key($operand1,$operand2); 3230 $cellIntersect = $oCol = $oRow = array(); 3231 foreach(array_keys($rowIntersect) as $row) { 3232 $oRow[] = $row; 3233 foreach($rowIntersect[$row] as $col => $data) { 3234 $oCol[] = PHPExcel_Cell::columnIndexFromString($col) - 1; 3235 $cellIntersect[$row] = array_intersect_key($operand1[$row],$operand2[$row]); 3236 } 3237 } 3238 $cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow); 3239 $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($cellIntersect)); 3240 $stack->push('Value',$cellIntersect,$cellRef); 3241 break; 3242 } 3243 3244 // if the token is a unary operator, pop one value off the stack, do the operation, and push it back on 3245 } elseif (($token === '~') || ($token === '%')) { 3246 // echo 'Token is a unary operator<br />'; 3247 if (($arg = $stack->pop()) === NULL) return $this->_raiseFormulaError('Internal error - Operand value missing from stack'); 3248 $arg = $arg['value']; 3249 if ($token === '~') { 3250 // echo 'Token is a negation operator<br />'; 3251 $this->_debugLog->writeDebugLog('Evaluating Negation of ', $this->_showValue($arg)); 3252 $multiplier = -1; 3253 } else { 3254 // echo 'Token is a percentile operator<br />'; 3255 $this->_debugLog->writeDebugLog('Evaluating Percentile of ', $this->_showValue($arg)); 3256 $multiplier = 0.01; 3257 } 3258 if (is_array($arg)) { 3259 self::_checkMatrixOperands($arg,$multiplier,2); 3260 try { 3261 $matrix1 = new PHPExcel_Shared_JAMA_Matrix($arg); 3262 $matrixResult = $matrix1->arrayTimesEquals($multiplier); 3263 $result = $matrixResult->getArray(); 3264 } catch (PHPExcel_Exception $ex) { 3265 $this->_debugLog->writeDebugLog('JAMA Matrix Exception: ', $ex->getMessage()); 3266 $result = '#VALUE!'; 3267 } 3268 $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($result)); 3269 $stack->push('Value',$result); 3270 } else { 3271 $this->_executeNumericBinaryOperation($cellID,$multiplier,$arg,'*','arrayTimesEquals',$stack); 3272 } 3273 3274 } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $token, $matches)) { 3275 $cellRef = NULL; 3276 // echo 'Element '.$token.' is a Cell reference<br />'; 3277 if (isset($matches[8])) { 3278 // echo 'Reference is a Range of cells<br />'; 3279 if ($pCell === NULL) { 3280 // We can't access the range, so return a REF error 3281 $cellValue = PHPExcel_Calculation_Functions::REF(); 3282 } else { 3283 $cellRef = $matches[6].$matches[7].':'.$matches[9].$matches[10]; 3284 if ($matches[2] > '') { 3285 $matches[2] = trim($matches[2],"\"'"); 3286 if ((strpos($matches[2],'[') !== FALSE) || (strpos($matches[2],']') !== FALSE)) { 3287 // It's a Reference to an external workbook (not currently supported) 3288 return $this->_raiseFormulaError('Unable to access External Workbook'); 3289 } 3290 $matches[2] = trim($matches[2],"\"'"); 3291 // echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'<br />'; 3292 $this->_debugLog->writeDebugLog('Evaluating Cell Range ', $cellRef, ' in worksheet ', $matches[2]); 3293 if ($pCellParent !== NULL) { 3294 $cellValue = $this->extractCellRange($cellRef, $this->_workbook->getSheetByName($matches[2]), FALSE); 3295 } else { 3296 return $this->_raiseFormulaError('Unable to access Cell Reference'); 3297 } 3298 $this->_debugLog->writeDebugLog('Evaluation Result for cells ', $cellRef, ' in worksheet ', $matches[2], ' is ', $this->_showTypeDetails($cellValue)); 3299 // $cellRef = $matches[2].'!'.$cellRef; 3300 } else { 3301 // echo '$cellRef='.$cellRef.' in current worksheet<br />'; 3302 $this->_debugLog->writeDebugLog('Evaluating Cell Range ', $cellRef, ' in current worksheet'); 3303 if ($pCellParent !== NULL) { 3304 $cellValue = $this->extractCellRange($cellRef, $pCellWorksheet, FALSE); 3305 } else { 3306 return $this->_raiseFormulaError('Unable to access Cell Reference'); 3307 } 3308 $this->_debugLog->writeDebugLog('Evaluation Result for cells ', $cellRef, ' is ', $this->_showTypeDetails($cellValue)); 3309 } 3310 } 3311 } else { 3312 // echo 'Reference is a single Cell<br />'; 3313 if ($pCell === NULL) { 3314 // We can't access the cell, so return a REF error 3315 $cellValue = PHPExcel_Calculation_Functions::REF(); 3316 } else { 3317 $cellRef = $matches[6].$matches[7]; 3318 if ($matches[2] > '') { 3319 $matches[2] = trim($matches[2],"\"'"); 3320 if ((strpos($matches[2],'[') !== FALSE) || (strpos($matches[2],']') !== FALSE)) { 3321 // It's a Reference to an external workbook (not currently supported) 3322 return $this->_raiseFormulaError('Unable to access External Workbook'); 3323 } 3324 // echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'<br />'; 3325 $this->_debugLog->writeDebugLog('Evaluating Cell ', $cellRef, ' in worksheet ', $matches[2]); 3326 if ($pCellParent !== NULL) { 3327 $cellSheet = $this->_workbook->getSheetByName($matches[2]); 3328 if ($cellSheet && $cellSheet->cellExists($cellRef)) { 3329 $cellValue = $this->extractCellRange($cellRef, $this->_workbook->getSheetByName($matches[2]), FALSE); 3330 $pCell->attach($pCellParent); 3331 } else { 3332 $cellValue = NULL; 3333 } 3334 } else { 3335 return $this->_raiseFormulaError('Unable to access Cell Reference'); 3336 } 3337 $this->_debugLog->writeDebugLog('Evaluation Result for cell ', $cellRef, ' in worksheet ', $matches[2], ' is ', $this->_showTypeDetails($cellValue)); 3338 // $cellRef = $matches[2].'!'.$cellRef; 3339 } else { 3340 // echo '$cellRef='.$cellRef.' in current worksheet<br />'; 3341 $this->_debugLog->writeDebugLog('Evaluating Cell ', $cellRef, ' in current worksheet'); 3342 if ($pCellParent->isDataSet($cellRef)) { 3343 $cellValue = $this->extractCellRange($cellRef, $pCellWorksheet, FALSE); 3344 $pCell->attach($pCellParent); 3345 } else { 3346 $cellValue = NULL; 3347 } 3348 $this->_debugLog->writeDebugLog('Evaluation Result for cell ', $cellRef, ' is ', $this->_showTypeDetails($cellValue)); 3349 } 3350 } 3351 } 3352 $stack->push('Value',$cellValue,$cellRef); 3353 3354 // if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on 3355 } elseif (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $token, $matches)) { 3356 // echo 'Token is a function<br />'; 3357 $functionName = $matches[1]; 3358 $argCount = $stack->pop(); 3359 $argCount = $argCount['value']; 3360 if ($functionName != 'MKMATRIX') { 3361 $this->_debugLog->writeDebugLog('Evaluating Function ', self::_localeFunc($functionName), '() with ', (($argCount == 0) ? 'no' : $argCount), ' argument', (($argCount == 1) ? '' : 's')); 3362 } 3363 if ((isset(self::$_PHPExcelFunctions[$functionName])) || (isset(self::$_controlFunctions[$functionName]))) { // function 3364 if (isset(self::$_PHPExcelFunctions[$functionName])) { 3365 $functionCall = self::$_PHPExcelFunctions[$functionName]['functionCall']; 3366 $passByReference = isset(self::$_PHPExcelFunctions[$functionName]['passByReference']); 3367 $passCellReference = isset(self::$_PHPExcelFunctions[$functionName]['passCellReference']); 3368 } elseif (isset(self::$_controlFunctions[$functionName])) { 3369 $functionCall = self::$_controlFunctions[$functionName]['functionCall']; 3370 $passByReference = isset(self::$_controlFunctions[$functionName]['passByReference']); 3371 $passCellReference = isset(self::$_controlFunctions[$functionName]['passCellReference']); 3372 } 3373 // get the arguments for this function 3374 // echo 'Function '.$functionName.' expects '.$argCount.' arguments<br />'; 3375 $args = $argArrayVals = array(); 3376 for ($i = 0; $i < $argCount; ++$i) { 3377 $arg = $stack->pop(); 3378 $a = $argCount - $i - 1; 3379 if (($passByReference) && 3380 (isset(self::$_PHPExcelFunctions[$functionName]['passByReference'][$a])) && 3381 (self::$_PHPExcelFunctions[$functionName]['passByReference'][$a])) { 3382 if ($arg['reference'] === NULL) { 3383 $args[] = $cellID; 3384 if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($cellID); } 3385 } else { 3386 $args[] = $arg['reference']; 3387 if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($arg['reference']); } 3388 } 3389 } else { 3390 $args[] = self::_unwrapResult($arg['value']); 3391 if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($arg['value']); } 3392 } 3393 } 3394 // Reverse the order of the arguments 3395 krsort($args); 3396 if (($passByReference) && ($argCount == 0)) { 3397 $args[] = $cellID; 3398 $argArrayVals[] = $this->_showValue($cellID); 3399 } 3400 // echo 'Arguments are: '; 3401 // print_r($args); 3402 // echo '<br />'; 3403 if ($functionName != 'MKMATRIX') { 3404 if ($this->_debugLog->getWriteDebugLog()) { 3405 krsort($argArrayVals); 3406 $this->_debugLog->writeDebugLog('Evaluating ', self::_localeFunc($functionName), '( ', implode(self::$_localeArgumentSeparator.' ',PHPExcel_Calculation_Functions::flattenArray($argArrayVals)), ' )'); 3407 } 3408 } 3409 // Process each argument in turn, building the return value as an array 3410 // if (($argCount == 1) && (is_array($args[1])) && ($functionName != 'MKMATRIX')) { 3411 // $operand1 = $args[1]; 3412 // $this->_debugLog->writeDebugLog('Argument is a matrix: ', $this->_showValue($operand1)); 3413 // $result = array(); 3414 // $row = 0; 3415 // foreach($operand1 as $args) { 3416 // if (is_array($args)) { 3417 // foreach($args as $arg) { 3418 // $this->_debugLog->writeDebugLog('Evaluating ', self::_localeFunc($functionName), '( ', $this->_showValue($arg), ' )'); 3419 // $r = call_user_func_array($functionCall,$arg); 3420 // $this->_debugLog->writeDebugLog('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($r)); 3421 // $result[$row][] = $r; 3422 // } 3423 // ++$row; 3424 // } else { 3425 // $this->_debugLog->writeDebugLog('Evaluating ', self::_localeFunc($functionName), '( ', $this->_showValue($args), ' )'); 3426 // $r = call_user_func_array($functionCall,$args); 3427 // $this->_debugLog->writeDebugLog('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($r)); 3428 // $result[] = $r; 3429 // } 3430 // } 3431 // } else { 3432 // Process the argument with the appropriate function call 3433 if ($passCellReference) { 3434 $args[] = $pCell; 3435 } 3436 if (strpos($functionCall,'::') !== FALSE) { 3437 $result = call_user_func_array(explode('::',$functionCall),$args); 3438 } else { 3439 foreach($args as &$arg) { 3440 $arg = PHPExcel_Calculation_Functions::flattenSingleValue($arg); 3441 } 3442 unset($arg); 3443 $result = call_user_func_array($functionCall,$args); 3444 } 3445 // } 3446 if ($functionName != 'MKMATRIX') { 3447 $this->_debugLog->writeDebugLog('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($result)); 3448 } 3449 $stack->push('Value',self::_wrapResult($result)); 3450 } 3451 3452 } else { 3453 // if the token is a number, boolean, string or an Excel error, push it onto the stack 3454 if (isset(self::$_ExcelConstants[strtoupper($token)])) { 3455 $excelConstant = strtoupper($token); 3456 // echo 'Token is a PHPExcel constant: '.$excelConstant.'<br />'; 3457 $stack->push('Constant Value',self::$_ExcelConstants[$excelConstant]); 3458 $this->_debugLog->writeDebugLog('Evaluating Constant ', $excelConstant, ' as ', $this->_showTypeDetails(self::$_ExcelConstants[$excelConstant])); 3459 } elseif ((is_numeric($token)) || ($token === NULL) || (is_bool($token)) || ($token == '') || ($token{0} == '"') || ($token{0} == '#')) { 3460 // echo 'Token is a number, boolean, string, null or an Excel error<br />'; 3461 $stack->push('Value',$token); 3462 // if the token is a named range, push the named range name onto the stack 3463 } elseif (preg_match('/^'.self::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $token, $matches)) { 3464 // echo 'Token is a named range<br />'; 3465 $namedRange = $matches[6]; 3466 // echo 'Named Range is '.$namedRange.'<br />'; 3467 $this->_debugLog->writeDebugLog('Evaluating Named Range ', $namedRange); 3468 $cellValue = $this->extractNamedRange($namedRange, ((NULL !== $pCell) ? $pCellWorksheet : NULL), FALSE); 3469 $pCell->attach($pCellParent); 3470 $this->_debugLog->writeDebugLog('Evaluation Result for named range ', $namedRange, ' is ', $this->_showTypeDetails($cellValue)); 3471 $stack->push('Named Range',$cellValue,$namedRange); 3472 } else { 3473 return $this->_raiseFormulaError("undefined variable '$token'"); 3474 } 3475 } 3476 } 3477 // when we're out of tokens, the stack should have a single element, the final result 3478 if ($stack->count() != 1) return $this->_raiseFormulaError("internal error"); 3479 $output = $stack->pop(); 3480 $output = $output['value']; 3481 3482 // if ((is_array($output)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) { 3483 // return array_shift(PHPExcel_Calculation_Functions::flattenArray($output)); 3484 // } 3485 return $output; 3486 } // function _processTokenStack() 3487 3488 3489 private function _validateBinaryOperand($cellID, &$operand, &$stack) { 3490 if (is_array($operand)) { 3491 if ((count($operand, COUNT_RECURSIVE) - count($operand)) == 1) { 3492 do { 3493 $operand = array_pop($operand); 3494 } while (is_array($operand)); 3495 } 3496 } 3497 // Numbers, matrices and booleans can pass straight through, as they're already valid 3498 if (is_string($operand)) { 3499 // We only need special validations for the operand if it is a string 3500 // Start by stripping off the quotation marks we use to identify true excel string values internally 3501 if ($operand > '' && $operand{0} == '"') { $operand = self::_unwrapResult($operand); } 3502 // If the string is a numeric value, we treat it as a numeric, so no further testing 3503 if (!is_numeric($operand)) { 3504 // If not a numeric, test to see if the value is an Excel error, and so can't be used in normal binary operations 3505 if ($operand > '' && $operand{0} == '#') { 3506 $stack->push('Value', $operand); 3507 $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($operand)); 3508 return FALSE; 3509 } elseif (!PHPExcel_Shared_String::convertToNumberIfFraction($operand)) { 3510 // If not a numeric or a fraction, then it's a text string, and so can't be used in mathematical binary operations 3511 $stack->push('Value', '#VALUE!'); 3512 $this->_debugLog->writeDebugLog('Evaluation Result is a ', $this->_showTypeDetails('#VALUE!')); 3513 return FALSE; 3514 } 3515 } 3516 } 3517 3518 // return a true if the value of the operand is one that we can use in normal binary operations 3519 return TRUE; 3520 } // function _validateBinaryOperand() 3521 3522 3523 private function _executeBinaryComparisonOperation($cellID, $operand1, $operand2, $operation, &$stack, $recursingArrays=FALSE) { 3524 // If we're dealing with matrix operations, we want a matrix result 3525 if ((is_array($operand1)) || (is_array($operand2))) { 3526 $result = array(); 3527 if ((is_array($operand1)) && (!is_array($operand2))) { 3528 foreach($operand1 as $x => $operandData) { 3529 $this->_debugLog->writeDebugLog('Evaluating Comparison ', $this->_showValue($operandData), ' ', $operation, ' ', $this->_showValue($operand2)); 3530 $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2,$operation,$stack); 3531 $r = $stack->pop(); 3532 $result[$x] = $r['value']; 3533 } 3534 } elseif ((!is_array($operand1)) && (is_array($operand2))) { 3535 foreach($operand2 as $x => $operandData) { 3536 $this->_debugLog->writeDebugLog('Evaluating Comparison ', $this->_showValue($operand1), ' ', $operation, ' ', $this->_showValue($operandData)); 3537 $this->_executeBinaryComparisonOperation($cellID,$operand1,$operandData,$operation,$stack); 3538 $r = $stack->pop(); 3539 $result[$x] = $r['value']; 3540 } 3541 } else { 3542 if (!$recursingArrays) { self::_checkMatrixOperands($operand1,$operand2,2); } 3543 foreach($operand1 as $x => $operandData) { 3544 $this->_debugLog->writeDebugLog('Evaluating Comparison ', $this->_showValue($operandData), ' ', $operation, ' ', $this->_showValue($operand2[$x])); 3545 $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2[$x],$operation,$stack,TRUE); 3546 $r = $stack->pop(); 3547 $result[$x] = $r['value']; 3548 } 3549 } 3550 // Log the result details 3551 $this->_debugLog->writeDebugLog('Comparison Evaluation Result is ', $this->_showTypeDetails($result)); 3552 // And push the result onto the stack 3553 $stack->push('Array',$result); 3554 return TRUE; 3555 } 3556 3557 // Simple validate the two operands if they are string values 3558 if (is_string($operand1) && $operand1 > '' && $operand1{0} == '"') { $operand1 = self::_unwrapResult($operand1); } 3559 if (is_string($operand2) && $operand2 > '' && $operand2{0} == '"') { $operand2 = self::_unwrapResult($operand2); } 3560 3561 // Use case insensitive comparaison if not OpenOffice mode 3562 if (PHPExcel_Calculation_Functions::getCompatibilityMode() != PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) 3563 { 3564 if (is_string($operand1)) { 3565 $operand1 = strtoupper($operand1); 3566 } 3567 3568 if (is_string($operand2)) { 3569 $operand2 = strtoupper($operand2); 3570 } 3571 } 3572 3573 $useLowercaseFirstComparison = is_string($operand1) && is_string($operand2) && PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE; 3574 3575 // execute the necessary operation 3576 switch ($operation) { 3577 // Greater than 3578 case '>': 3579 if ($useLowercaseFirstComparison) { 3580 $result = $this->strcmpLowercaseFirst($operand1, $operand2) > 0; 3581 } else { 3582 $result = ($operand1 > $operand2); 3583 } 3584 break; 3585 // Less than 3586 case '<': 3587 if ($useLowercaseFirstComparison) { 3588 $result = $this->strcmpLowercaseFirst($operand1, $operand2) < 0; 3589 } else { 3590 $result = ($operand1 < $operand2); 3591 } 3592 break; 3593 // Equality 3594 case '=': 3595 $result = ($operand1 == $operand2); 3596 break; 3597 // Greater than or equal 3598 case '>=': 3599 if ($useLowercaseFirstComparison) { 3600 $result = $this->strcmpLowercaseFirst($operand1, $operand2) >= 0; 3601 } else { 3602 $result = ($operand1 >= $operand2); 3603 } 3604 break; 3605 // Less than or equal 3606 case '<=': 3607 if ($useLowercaseFirstComparison) { 3608 $result = $this->strcmpLowercaseFirst($operand1, $operand2) <= 0; 3609 } else { 3610 $result = ($operand1 <= $operand2); 3611 } 3612 break; 3613 // Inequality 3614 case '<>': 3615 $result = ($operand1 != $operand2); 3616 break; 3617 } 3618 3619 // Log the result details 3620 $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($result)); 3621 // And push the result onto the stack 3622 $stack->push('Value',$result); 3623 return TRUE; 3624 } // function _executeBinaryComparisonOperation() 3625 3626 /** 3627 * Compare two strings in the same way as strcmp() except that lowercase come before uppercase letters 3628 * @param string $str1 3629 * @param string $str2 3630 * @return integer 3631 */ 3632 private function strcmpLowercaseFirst($str1, $str2) 3633 { 3634 $from = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 3635 $to = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 3636 $inversedStr1 = strtr($str1, $from, $to); 3637 $inversedStr2 = strtr($str2, $from, $to); 3638 3639 return strcmp($inversedStr1, $inversedStr2); 3640 } 3641 3642 private function _executeNumericBinaryOperation($cellID,$operand1,$operand2,$operation,$matrixFunction,&$stack) { 3643 // Validate the two operands 3644 if (!$this->_validateBinaryOperand($cellID,$operand1,$stack)) return FALSE; 3645 if (!$this->_validateBinaryOperand($cellID,$operand2,$stack)) return FALSE; 3646 3647 // If either of the operands is a matrix, we need to treat them both as matrices 3648 // (converting the other operand to a matrix if need be); then perform the required 3649 // matrix operation 3650 if ((is_array($operand1)) || (is_array($operand2))) { 3651 // Ensure that both operands are arrays/matrices of the same size 3652 self::_checkMatrixOperands($operand1, $operand2, 2); 3653 3654 try { 3655 // Convert operand 1 from a PHP array to a matrix 3656 $matrix = new PHPExcel_Shared_JAMA_Matrix($operand1); 3657 // Perform the required operation against the operand 1 matrix, passing in operand 2 3658 $matrixResult = $matrix->$matrixFunction($operand2); 3659 $result = $matrixResult->getArray(); 3660 } catch (PHPExcel_Exception $ex) { 3661 $this->_debugLog->writeDebugLog('JAMA Matrix Exception: ', $ex->getMessage()); 3662 $result = '#VALUE!'; 3663 } 3664 } else { 3665 if ((PHPExcel_Calculation_Functions::getCompatibilityMode() != PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) && 3666 ((is_string($operand1) && !is_numeric($operand1) && strlen($operand1)>0) || 3667 (is_string($operand2) && !is_numeric($operand2) && strlen($operand2)>0))) { 3668 $result = PHPExcel_Calculation_Functions::VALUE(); 3669 } else { 3670 // If we're dealing with non-matrix operations, execute the necessary operation 3671 switch ($operation) { 3672 // Addition 3673 case '+': 3674 $result = $operand1 + $operand2; 3675 break; 3676 // Subtraction 3677 case '-': 3678 $result = $operand1 - $operand2; 3679 break; 3680 // Multiplication 3681 case '*': 3682 $result = $operand1 * $operand2; 3683 break; 3684 // Division 3685 case '/': 3686 if ($operand2 == 0) { 3687 // Trap for Divide by Zero error 3688 $stack->push('Value','#DIV/0!'); 3689 $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails('#DIV/0!')); 3690 return FALSE; 3691 } else { 3692 $result = $operand1 / $operand2; 3693 } 3694 break; 3695 // Power 3696 case '^': 3697 $result = pow($operand1, $operand2); 3698 break; 3699 } 3700 } 3701 } 3702 3703 // Log the result details 3704 $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($result)); 3705 // And push the result onto the stack 3706 $stack->push('Value',$result); 3707 return TRUE; 3708 } // function _executeNumericBinaryOperation() 3709 3710 3711 // trigger an error, but nicely, if need be 3712 protected function _raiseFormulaError($errorMessage) { 3713 $this->formulaError = $errorMessage; 3714 $this->_cyclicReferenceStack->clear(); 3715 if (!$this->suppressFormulaErrors) throw new PHPExcel_Calculation_Exception($errorMessage); 3716 trigger_error($errorMessage, E_USER_ERROR); 3717 } // function _raiseFormulaError() 3718 3719 3720 /** 3721 * Extract range values 3722 * 3723 * @param string &$pRange String based range representation 3724 * @param PHPExcel_Worksheet $pSheet Worksheet 3725 * @param boolean $resetLog Flag indicating whether calculation log should be reset or not 3726 * @return mixed Array of values in range if range contains more than one element. Otherwise, a single value is returned. 3727 * @throws PHPExcel_Calculation_Exception 3728 */ 3729 public function extractCellRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = NULL, $resetLog = TRUE) { 3730 // Return value 3731 $returnValue = array (); 3732 3733 // echo 'extractCellRange('.$pRange.')',PHP_EOL; 3734 if ($pSheet !== NULL) { 3735 $pSheetName = $pSheet->getTitle(); 3736 // echo 'Passed sheet name is '.$pSheetName.PHP_EOL; 3737 // echo 'Range reference is '.$pRange.PHP_EOL; 3738 if (strpos ($pRange, '!') !== false) { 3739 // echo '$pRange reference includes sheet reference',PHP_EOL; 3740 list($pSheetName,$pRange) = PHPExcel_Worksheet::extractSheetTitle($pRange, true); 3741 // echo 'New sheet name is '.$pSheetName,PHP_EOL; 3742 // echo 'Adjusted Range reference is '.$pRange,PHP_EOL; 3743 $pSheet = $this->_workbook->getSheetByName($pSheetName); 3744 } 3745 3746 // Extract range 3747 $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange); 3748 $pRange = $pSheetName.'!'.$pRange; 3749 if (!isset($aReferences[1])) { 3750 // Single cell in range 3751 sscanf($aReferences[0],'%[A-Z]%d', $currentCol, $currentRow); 3752 $cellValue = NULL; 3753 if ($pSheet->cellExists($aReferences[0])) { 3754 $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog); 3755 } else { 3756 $returnValue[$currentRow][$currentCol] = NULL; 3757 } 3758 } else { 3759 // Extract cell data for all cells in the range 3760 foreach ($aReferences as $reference) { 3761 // Extract range 3762 sscanf($reference,'%[A-Z]%d', $currentCol, $currentRow); 3763 $cellValue = NULL; 3764 if ($pSheet->cellExists($reference)) { 3765 $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog); 3766 } else { 3767 $returnValue[$currentRow][$currentCol] = NULL; 3768 } 3769 } 3770 } 3771 } 3772 3773 // Return 3774 return $returnValue; 3775 } // function extractCellRange() 3776 3777 3778 /** 3779 * Extract range values 3780 * 3781 * @param string &$pRange String based range representation 3782 * @param PHPExcel_Worksheet $pSheet Worksheet 3783 * @return mixed Array of values in range if range contains more than one element. Otherwise, a single value is returned. 3784 * @param boolean $resetLog Flag indicating whether calculation log should be reset or not 3785 * @throws PHPExcel_Calculation_Exception 3786 */ 3787 public function extractNamedRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = NULL, $resetLog = TRUE) { 3788 // Return value 3789 $returnValue = array (); 3790 3791 // echo 'extractNamedRange('.$pRange.')<br />'; 3792 if ($pSheet !== NULL) { 3793 $pSheetName = $pSheet->getTitle(); 3794 // echo 'Current sheet name is '.$pSheetName.'<br />'; 3795 // echo 'Range reference is '.$pRange.'<br />'; 3796 if (strpos ($pRange, '!') !== false) { 3797 // echo '$pRange reference includes sheet reference',PHP_EOL; 3798 list($pSheetName,$pRange) = PHPExcel_Worksheet::extractSheetTitle($pRange, true); 3799 // echo 'New sheet name is '.$pSheetName,PHP_EOL; 3800 // echo 'Adjusted Range reference is '.$pRange,PHP_EOL; 3801 $pSheet = $this->_workbook->getSheetByName($pSheetName); 3802 } 3803 3804 // Named range? 3805 $namedRange = PHPExcel_NamedRange::resolveRange($pRange, $pSheet); 3806 if ($namedRange !== NULL) { 3807 $pSheet = $namedRange->getWorksheet(); 3808 // echo 'Named Range '.$pRange.' ('; 3809 $pRange = $namedRange->getRange(); 3810 $splitRange = PHPExcel_Cell::splitRange($pRange); 3811 // Convert row and column references 3812 if (ctype_alpha($splitRange[0][0])) { 3813 $pRange = $splitRange[0][0] . '1:' . $splitRange[0][1] . $namedRange->getWorksheet()->getHighestRow(); 3814 } elseif(ctype_digit($splitRange[0][0])) { 3815 $pRange = 'A' . $splitRange[0][0] . ':' . $namedRange->getWorksheet()->getHighestColumn() . $splitRange[0][1]; 3816 } 3817 // echo $pRange.') is in sheet '.$namedRange->getWorksheet()->getTitle().'<br />'; 3818 3819 // if ($pSheet->getTitle() != $namedRange->getWorksheet()->getTitle()) { 3820 // if (!$namedRange->getLocalOnly()) { 3821 // $pSheet = $namedRange->getWorksheet(); 3822 // } else { 3823 // return $returnValue; 3824 // } 3825 // } 3826 } else { 3827 return PHPExcel_Calculation_Functions::REF(); 3828 } 3829 3830 // Extract range 3831 $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange); 3832 // var_dump($aReferences); 3833 if (!isset($aReferences[1])) { 3834 // Single cell (or single column or row) in range 3835 list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($aReferences[0]); 3836 $cellValue = NULL; 3837 if ($pSheet->cellExists($aReferences[0])) { 3838 $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog); 3839 } else { 3840 $returnValue[$currentRow][$currentCol] = NULL; 3841 } 3842 } else { 3843 // Extract cell data for all cells in the range 3844 foreach ($aReferences as $reference) { 3845 // Extract range 3846 list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($reference); 3847 // echo 'NAMED RANGE: $currentCol='.$currentCol.' $currentRow='.$currentRow.'<br />'; 3848 $cellValue = NULL; 3849 if ($pSheet->cellExists($reference)) { 3850 $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog); 3851 } else { 3852 $returnValue[$currentRow][$currentCol] = NULL; 3853 } 3854 } 3855 } 3856 // print_r($returnValue); 3857 // echo '<br />'; 3858 } 3859 3860 // Return 3861 return $returnValue; 3862 } // function extractNamedRange() 3863 3864 3865 /** 3866 * Is a specific function implemented? 3867 * 3868 * @param string $pFunction Function Name 3869 * @return boolean 3870 */ 3871 public function isImplemented($pFunction = '') { 3872 $pFunction = strtoupper ($pFunction); 3873 if (isset(self::$_PHPExcelFunctions[$pFunction])) { 3874 return (self::$_PHPExcelFunctions[$pFunction]['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY'); 3875 } else { 3876 return FALSE; 3877 } 3878 } // function isImplemented() 3879 3880 3881 /** 3882 * Get a list of all implemented functions as an array of function objects 3883 * 3884 * @return array of PHPExcel_Calculation_Function 3885 */ 3886 public function listFunctions() { 3887 // Return value 3888 $returnValue = array(); 3889 // Loop functions 3890 foreach(self::$_PHPExcelFunctions as $functionName => $function) { 3891 if ($function['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY') { 3892 $returnValue[$functionName] = new PHPExcel_Calculation_Function($function['category'], 3893 $functionName, 3894 $function['functionCall'] 3895 ); 3896 } 3897 } 3898 3899 // Return 3900 return $returnValue; 3901 } // function listFunctions() 3902 3903 3904 /** 3905 * Get a list of all Excel function names 3906 * 3907 * @return array 3908 */ 3909 public function listAllFunctionNames() { 3910 return array_keys(self::$_PHPExcelFunctions); 3911 } // function listAllFunctionNames() 3912 3913 /** 3914 * Get a list of implemented Excel function names 3915 * 3916 * @return array 3917 */ 3918 public function listFunctionNames() { 3919 // Return value 3920 $returnValue = array(); 3921 // Loop functions 3922 foreach(self::$_PHPExcelFunctions as $functionName => $function) { 3923 if ($function['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY') { 3924 $returnValue[] = $functionName; 3925 } 3926 } 3927 3928 // Return 3929 return $returnValue; 3930 } // function listFunctionNames() 3931 3932 } // class PHPExcel_Calculation 3933
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |