Calculation.php 171 KB

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