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