For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

760 lines
20 KiB

  1. <?php
  2. /** PHPExcel root directory */
  3. if (!defined('PHPEXCEL_ROOT')) {
  4. /**
  5. * @ignore
  6. */
  7. define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
  8. require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
  9. }
  10. /** MAX_VALUE */
  11. define('MAX_VALUE', 1.2e308);
  12. /** 2 / PI */
  13. define('M_2DIVPI', 0.63661977236758134307553505349006);
  14. /** MAX_ITERATIONS */
  15. define('MAX_ITERATIONS', 256);
  16. /** PRECISION */
  17. define('PRECISION', 8.88E-016);
  18. /**
  19. * PHPExcel_Calculation_Functions
  20. *
  21. * Copyright (c) 2006 - 2015 PHPExcel
  22. *
  23. * This library is free software; you can redistribute it and/or
  24. * modify it under the terms of the GNU Lesser General Public
  25. * License as published by the Free Software Foundation; either
  26. * version 2.1 of the License, or (at your option) any later version.
  27. *
  28. * This library is distributed in the hope that it will be useful,
  29. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  31. * Lesser General Public License for more details.
  32. *
  33. * You should have received a copy of the GNU Lesser General Public
  34. * License along with this library; if not, write to the Free Software
  35. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  36. *
  37. * @category PHPExcel
  38. * @package PHPExcel_Calculation
  39. * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  40. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  41. * @version ##VERSION##, ##DATE##
  42. */
  43. class PHPExcel_Calculation_Functions
  44. {
  45. /** constants */
  46. const COMPATIBILITY_EXCEL = 'Excel';
  47. const COMPATIBILITY_GNUMERIC = 'Gnumeric';
  48. const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
  49. const RETURNDATE_PHP_NUMERIC = 'P';
  50. const RETURNDATE_PHP_OBJECT = 'O';
  51. const RETURNDATE_EXCEL = 'E';
  52. /**
  53. * Compatibility mode to use for error checking and responses
  54. *
  55. * @access private
  56. * @var string
  57. */
  58. protected static $compatibilityMode = self::COMPATIBILITY_EXCEL;
  59. /**
  60. * Data Type to use when returning date values
  61. *
  62. * @access private
  63. * @var string
  64. */
  65. protected static $returnDateType = self::RETURNDATE_EXCEL;
  66. /**
  67. * List of error codes
  68. *
  69. * @access private
  70. * @var array
  71. */
  72. protected static $errorCodes = array(
  73. 'null' => '#NULL!',
  74. 'divisionbyzero' => '#DIV/0!',
  75. 'value' => '#VALUE!',
  76. 'reference' => '#REF!',
  77. 'name' => '#NAME?',
  78. 'num' => '#NUM!',
  79. 'na' => '#N/A',
  80. 'gettingdata' => '#GETTING_DATA'
  81. );
  82. /**
  83. * Set the Compatibility Mode
  84. *
  85. * @access public
  86. * @category Function Configuration
  87. * @param string $compatibilityMode Compatibility Mode
  88. * Permitted values are:
  89. * PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL 'Excel'
  90. * PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC 'Gnumeric'
  91. * PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc'
  92. * @return boolean (Success or Failure)
  93. */
  94. public static function setCompatibilityMode($compatibilityMode)
  95. {
  96. if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
  97. ($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
  98. ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  99. self::$compatibilityMode = $compatibilityMode;
  100. return true;
  101. }
  102. return false;
  103. }
  104. /**
  105. * Return the current Compatibility Mode
  106. *
  107. * @access public
  108. * @category Function Configuration
  109. * @return string Compatibility Mode
  110. * Possible Return values are:
  111. * PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL 'Excel'
  112. * PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC 'Gnumeric'
  113. * PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc'
  114. */
  115. public static function getCompatibilityMode()
  116. {
  117. return self::$compatibilityMode;
  118. }
  119. /**
  120. * Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
  121. *
  122. * @access public
  123. * @category Function Configuration
  124. * @param string $returnDateType Return Date Format
  125. * Permitted values are:
  126. * PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC 'P'
  127. * PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT 'O'
  128. * PHPExcel_Calculation_Functions::RETURNDATE_EXCEL 'E'
  129. * @return boolean Success or failure
  130. */
  131. public static function setReturnDateType($returnDateType)
  132. {
  133. if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
  134. ($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
  135. ($returnDateType == self::RETURNDATE_EXCEL)) {
  136. self::$returnDateType = $returnDateType;
  137. return true;
  138. }
  139. return false;
  140. }
  141. /**
  142. * Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
  143. *
  144. * @access public
  145. * @category Function Configuration
  146. * @return string Return Date Format
  147. * Possible Return values are:
  148. * PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC 'P'
  149. * PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT 'O'
  150. * PHPExcel_Calculation_Functions::RETURNDATE_EXCEL 'E'
  151. */
  152. public static function getReturnDateType()
  153. {
  154. return self::$returnDateType;
  155. }
  156. /**
  157. * DUMMY
  158. *
  159. * @access public
  160. * @category Error Returns
  161. * @return string #Not Yet Implemented
  162. */
  163. public static function DUMMY()
  164. {
  165. return '#Not Yet Implemented';
  166. }
  167. /**
  168. * DIV0
  169. *
  170. * @access public
  171. * @category Error Returns
  172. * @return string #Not Yet Implemented
  173. */
  174. public static function DIV0()
  175. {
  176. return self::$errorCodes['divisionbyzero'];
  177. }
  178. /**
  179. * NA
  180. *
  181. * Excel Function:
  182. * =NA()
  183. *
  184. * Returns the error value #N/A
  185. * #N/A is the error value that means "no value is available."
  186. *
  187. * @access public
  188. * @category Logical Functions
  189. * @return string #N/A!
  190. */
  191. public static function NA()
  192. {
  193. return self::$errorCodes['na'];
  194. }
  195. /**
  196. * NaN
  197. *
  198. * Returns the error value #NUM!
  199. *
  200. * @access public
  201. * @category Error Returns
  202. * @return string #NUM!
  203. */
  204. public static function NaN()
  205. {
  206. return self::$errorCodes['num'];
  207. }
  208. /**
  209. * NAME
  210. *
  211. * Returns the error value #NAME?
  212. *
  213. * @access public
  214. * @category Error Returns
  215. * @return string #NAME?
  216. */
  217. public static function NAME()
  218. {
  219. return self::$errorCodes['name'];
  220. }
  221. /**
  222. * REF
  223. *
  224. * Returns the error value #REF!
  225. *
  226. * @access public
  227. * @category Error Returns
  228. * @return string #REF!
  229. */
  230. public static function REF()
  231. {
  232. return self::$errorCodes['reference'];
  233. }
  234. /**
  235. * NULL
  236. *
  237. * Returns the error value #NULL!
  238. *
  239. * @access public
  240. * @category Error Returns
  241. * @return string #NULL!
  242. */
  243. public static function NULL()
  244. {
  245. return self::$errorCodes['null'];
  246. }
  247. /**
  248. * VALUE
  249. *
  250. * Returns the error value #VALUE!
  251. *
  252. * @access public
  253. * @category Error Returns
  254. * @return string #VALUE!
  255. */
  256. public static function VALUE()
  257. {
  258. return self::$errorCodes['value'];
  259. }
  260. public static function isMatrixValue($idx)
  261. {
  262. return ((substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0));
  263. }
  264. public static function isValue($idx)
  265. {
  266. return (substr_count($idx, '.') == 0);
  267. }
  268. public static function isCellValue($idx)
  269. {
  270. return (substr_count($idx, '.') > 1);
  271. }
  272. public static function ifCondition($condition)
  273. {
  274. $condition = PHPExcel_Calculation_Functions::flattenSingleValue($condition);
  275. if (!isset($condition[0])) {
  276. $condition = '=""';
  277. }
  278. if (!in_array($condition[0], array('>', '<', '='))) {
  279. if (!is_numeric($condition)) {
  280. $condition = PHPExcel_Calculation::wrapResult(strtoupper($condition));
  281. }
  282. return '=' . $condition;
  283. } else {
  284. preg_match('/([<>=]+)(.*)/', $condition, $matches);
  285. list(, $operator, $operand) = $matches;
  286. if (!is_numeric($operand)) {
  287. $operand = str_replace('"', '""', $operand);
  288. $operand = PHPExcel_Calculation::wrapResult(strtoupper($operand));
  289. }
  290. return $operator.$operand;
  291. }
  292. }
  293. /**
  294. * ERROR_TYPE
  295. *
  296. * @param mixed $value Value to check
  297. * @return boolean
  298. */
  299. public static function ERROR_TYPE($value = '')
  300. {
  301. $value = self::flattenSingleValue($value);
  302. $i = 1;
  303. foreach (self::$errorCodes as $errorCode) {
  304. if ($value === $errorCode) {
  305. return $i;
  306. }
  307. ++$i;
  308. }
  309. return self::NA();
  310. }
  311. /**
  312. * IS_BLANK
  313. *
  314. * @param mixed $value Value to check
  315. * @return boolean
  316. */
  317. public static function IS_BLANK($value = null)
  318. {
  319. if (!is_null($value)) {
  320. $value = self::flattenSingleValue($value);
  321. }
  322. return is_null($value);
  323. }
  324. /**
  325. * IS_ERR
  326. *
  327. * @param mixed $value Value to check
  328. * @return boolean
  329. */
  330. public static function IS_ERR($value = '')
  331. {
  332. $value = self::flattenSingleValue($value);
  333. return self::IS_ERROR($value) && (!self::IS_NA($value));
  334. }
  335. /**
  336. * IS_ERROR
  337. *
  338. * @param mixed $value Value to check
  339. * @return boolean
  340. */
  341. public static function IS_ERROR($value = '')
  342. {
  343. $value = self::flattenSingleValue($value);
  344. if (!is_string($value)) {
  345. return false;
  346. }
  347. return in_array($value, array_values(self::$errorCodes));
  348. }
  349. /**
  350. * IS_NA
  351. *
  352. * @param mixed $value Value to check
  353. * @return boolean
  354. */
  355. public static function IS_NA($value = '')
  356. {
  357. $value = self::flattenSingleValue($value);
  358. return ($value === self::NA());
  359. }
  360. /**
  361. * IS_EVEN
  362. *
  363. * @param mixed $value Value to check
  364. * @return boolean
  365. */
  366. public static function IS_EVEN($value = null)
  367. {
  368. $value = self::flattenSingleValue($value);
  369. if ($value === null) {
  370. return self::NAME();
  371. } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
  372. return self::VALUE();
  373. }
  374. return ($value % 2 == 0);
  375. }
  376. /**
  377. * IS_ODD
  378. *
  379. * @param mixed $value Value to check
  380. * @return boolean
  381. */
  382. public static function IS_ODD($value = null)
  383. {
  384. $value = self::flattenSingleValue($value);
  385. if ($value === null) {
  386. return self::NAME();
  387. } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
  388. return self::VALUE();
  389. }
  390. return (abs($value) % 2 == 1);
  391. }
  392. /**
  393. * IS_NUMBER
  394. *
  395. * @param mixed $value Value to check
  396. * @return boolean
  397. */
  398. public static function IS_NUMBER($value = null)
  399. {
  400. $value = self::flattenSingleValue($value);
  401. if (is_string($value)) {
  402. return false;
  403. }
  404. return is_numeric($value);
  405. }
  406. /**
  407. * IS_LOGICAL
  408. *
  409. * @param mixed $value Value to check
  410. * @return boolean
  411. */
  412. public static function IS_LOGICAL($value = null)
  413. {
  414. $value = self::flattenSingleValue($value);
  415. return is_bool($value);
  416. }
  417. /**
  418. * IS_TEXT
  419. *
  420. * @param mixed $value Value to check
  421. * @return boolean
  422. */
  423. public static function IS_TEXT($value = null)
  424. {
  425. $value = self::flattenSingleValue($value);
  426. return (is_string($value) && !self::IS_ERROR($value));
  427. }
  428. /**
  429. * IS_NONTEXT
  430. *
  431. * @param mixed $value Value to check
  432. * @return boolean
  433. */
  434. public static function IS_NONTEXT($value = null)
  435. {
  436. return !self::IS_TEXT($value);
  437. }
  438. /**
  439. * VERSION
  440. *
  441. * @return string Version information
  442. */
  443. public static function VERSION()
  444. {
  445. return 'PHPExcel ##VERSION##, ##DATE##';
  446. }
  447. /**
  448. * N
  449. *
  450. * Returns a value converted to a number
  451. *
  452. * @param value The value you want converted
  453. * @return number N converts values listed in the following table
  454. * If value is or refers to N returns
  455. * A number That number
  456. * A date The serial number of that date
  457. * TRUE 1
  458. * FALSE 0
  459. * An error value The error value
  460. * Anything else 0
  461. */
  462. public static function N($value = null)
  463. {
  464. while (is_array($value)) {
  465. $value = array_shift($value);
  466. }
  467. switch (gettype($value)) {
  468. case 'double':
  469. case 'float':
  470. case 'integer':
  471. return $value;
  472. case 'boolean':
  473. return (integer) $value;
  474. case 'string':
  475. // Errors
  476. if ((strlen($value) > 0) && ($value[0] == '#')) {
  477. return $value;
  478. }
  479. break;
  480. }
  481. return 0;
  482. }
  483. /**
  484. * TYPE
  485. *
  486. * Returns a number that identifies the type of a value
  487. *
  488. * @param value The value you want tested
  489. * @return number N converts values listed in the following table
  490. * If value is or refers to N returns
  491. * A number 1
  492. * Text 2
  493. * Logical Value 4
  494. * An error value 16
  495. * Array or Matrix 64
  496. */
  497. public static function TYPE($value = null)
  498. {
  499. $value = self::flattenArrayIndexed($value);
  500. if (is_array($value) && (count($value) > 1)) {
  501. end($value);
  502. $a = key($value);
  503. // Range of cells is an error
  504. if (self::isCellValue($a)) {
  505. return 16;
  506. // Test for Matrix
  507. } elseif (self::isMatrixValue($a)) {
  508. return 64;
  509. }
  510. } elseif (empty($value)) {
  511. // Empty Cell
  512. return 1;
  513. }
  514. $value = self::flattenSingleValue($value);
  515. if (($value === null) || (is_float($value)) || (is_int($value))) {
  516. return 1;
  517. } elseif (is_bool($value)) {
  518. return 4;
  519. } elseif (is_array($value)) {
  520. return 64;
  521. } elseif (is_string($value)) {
  522. // Errors
  523. if ((strlen($value) > 0) && ($value[0] == '#')) {
  524. return 16;
  525. }
  526. return 2;
  527. }
  528. return 0;
  529. }
  530. /**
  531. * Convert a multi-dimensional array to a simple 1-dimensional array
  532. *
  533. * @param array $array Array to be flattened
  534. * @return array Flattened array
  535. */
  536. public static function flattenArray($array)
  537. {
  538. if (!is_array($array)) {
  539. return (array) $array;
  540. }
  541. $arrayValues = array();
  542. foreach ($array as $value) {
  543. if (is_array($value)) {
  544. foreach ($value as $val) {
  545. if (is_array($val)) {
  546. foreach ($val as $v) {
  547. $arrayValues[] = $v;
  548. }
  549. } else {
  550. $arrayValues[] = $val;
  551. }
  552. }
  553. } else {
  554. $arrayValues[] = $value;
  555. }
  556. }
  557. return $arrayValues;
  558. }
  559. /**
  560. * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing
  561. *
  562. * @param array $array Array to be flattened
  563. * @return array Flattened array
  564. */
  565. public static function flattenArrayIndexed($array)
  566. {
  567. if (!is_array($array)) {
  568. return (array) $array;
  569. }
  570. $arrayValues = array();
  571. foreach ($array as $k1 => $value) {
  572. if (is_array($value)) {
  573. foreach ($value as $k2 => $val) {
  574. if (is_array($val)) {
  575. foreach ($val as $k3 => $v) {
  576. $arrayValues[$k1.'.'.$k2.'.'.$k3] = $v;
  577. }
  578. } else {
  579. $arrayValues[$k1.'.'.$k2] = $val;
  580. }
  581. }
  582. } else {
  583. $arrayValues[$k1] = $value;
  584. }
  585. }
  586. return $arrayValues;
  587. }
  588. /**
  589. * Convert an array to a single scalar value by extracting the first element
  590. *
  591. * @param mixed $value Array or scalar value
  592. * @return mixed
  593. */
  594. public static function flattenSingleValue($value = '')
  595. {
  596. while (is_array($value)) {
  597. $value = array_pop($value);
  598. }
  599. return $value;
  600. }
  601. }
  602. //
  603. // There are a few mathematical functions that aren't available on all versions of PHP for all platforms
  604. // These functions aren't available in Windows implementations of PHP prior to version 5.3.0
  605. // So we test if they do exist for this version of PHP/operating platform; and if not we create them
  606. //
  607. if (!function_exists('acosh')) {
  608. function acosh($x)
  609. {
  610. return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2));
  611. } // function acosh()
  612. }
  613. if (!function_exists('asinh')) {
  614. function asinh($x)
  615. {
  616. return log($x + sqrt(1 + $x * $x));
  617. } // function asinh()
  618. }
  619. if (!function_exists('atanh')) {
  620. function atanh($x)
  621. {
  622. return (log(1 + $x) - log(1 - $x)) / 2;
  623. } // function atanh()
  624. }
  625. //
  626. // Strangely, PHP doesn't have a mb_str_replace multibyte function
  627. // As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set
  628. //
  629. if ((!function_exists('mb_str_replace')) &&
  630. (function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos'))) {
  631. function mb_str_replace($search, $replace, $subject)
  632. {
  633. if (is_array($subject)) {
  634. $ret = array();
  635. foreach ($subject as $key => $val) {
  636. $ret[$key] = mb_str_replace($search, $replace, $val);
  637. }
  638. return $ret;
  639. }
  640. foreach ((array) $search as $key => $s) {
  641. if ($s == '' && $s !== 0) {
  642. continue;
  643. }
  644. $r = !is_array($replace) ? $replace : (array_key_exists($key, $replace) ? $replace[$key] : '');
  645. $pos = mb_strpos($subject, $s, 0, 'UTF-8');
  646. while ($pos !== false) {
  647. $subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), 65535, 'UTF-8');
  648. $pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8');
  649. }
  650. }
  651. return $subject;
  652. }
  653. }