|
|
- <?php
-
- /** PHPExcel root directory */
- if (!defined('PHPEXCEL_ROOT')) {
- /**
- * @ignore
- */
- define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
- require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
- }
-
-
- /** MAX_VALUE */
- define('MAX_VALUE', 1.2e308);
-
- /** 2 / PI */
- define('M_2DIVPI', 0.63661977236758134307553505349006);
-
- /** MAX_ITERATIONS */
- define('MAX_ITERATIONS', 256);
-
- /** PRECISION */
- define('PRECISION', 8.88E-016);
-
-
- /**
- * PHPExcel_Calculation_Functions
- *
- * Copyright (c) 2006 - 2015 PHPExcel
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * @category PHPExcel
- * @package PHPExcel_Calculation
- * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
- * @version ##VERSION##, ##DATE##
- */
- class PHPExcel_Calculation_Functions
- {
-
- /** constants */
- const COMPATIBILITY_EXCEL = 'Excel';
- const COMPATIBILITY_GNUMERIC = 'Gnumeric';
- const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
-
- const RETURNDATE_PHP_NUMERIC = 'P';
- const RETURNDATE_PHP_OBJECT = 'O';
- const RETURNDATE_EXCEL = 'E';
-
-
- /**
- * Compatibility mode to use for error checking and responses
- *
- * @access private
- * @var string
- */
- protected static $compatibilityMode = self::COMPATIBILITY_EXCEL;
-
- /**
- * Data Type to use when returning date values
- *
- * @access private
- * @var string
- */
- protected static $returnDateType = self::RETURNDATE_EXCEL;
-
- /**
- * List of error codes
- *
- * @access private
- * @var array
- */
- protected static $errorCodes = array(
- 'null' => '#NULL!',
- 'divisionbyzero' => '#DIV/0!',
- 'value' => '#VALUE!',
- 'reference' => '#REF!',
- 'name' => '#NAME?',
- 'num' => '#NUM!',
- 'na' => '#N/A',
- 'gettingdata' => '#GETTING_DATA'
- );
-
-
- /**
- * Set the Compatibility Mode
- *
- * @access public
- * @category Function Configuration
- * @param string $compatibilityMode Compatibility Mode
- * Permitted values are:
- * PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL 'Excel'
- * PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC 'Gnumeric'
- * PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc'
- * @return boolean (Success or Failure)
- */
- public static function setCompatibilityMode($compatibilityMode)
- {
- if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
- ($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
- ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
- self::$compatibilityMode = $compatibilityMode;
- return true;
- }
- return false;
- }
-
-
- /**
- * Return the current Compatibility Mode
- *
- * @access public
- * @category Function Configuration
- * @return string Compatibility Mode
- * Possible Return values are:
- * PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL 'Excel'
- * PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC 'Gnumeric'
- * PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc'
- */
- public static function getCompatibilityMode()
- {
- return self::$compatibilityMode;
- }
-
-
- /**
- * Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
- *
- * @access public
- * @category Function Configuration
- * @param string $returnDateType Return Date Format
- * Permitted values are:
- * PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC 'P'
- * PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT 'O'
- * PHPExcel_Calculation_Functions::RETURNDATE_EXCEL 'E'
- * @return boolean Success or failure
- */
- public static function setReturnDateType($returnDateType)
- {
- if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
- ($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
- ($returnDateType == self::RETURNDATE_EXCEL)) {
- self::$returnDateType = $returnDateType;
- return true;
- }
- return false;
- }
-
-
- /**
- * Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
- *
- * @access public
- * @category Function Configuration
- * @return string Return Date Format
- * Possible Return values are:
- * PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC 'P'
- * PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT 'O'
- * PHPExcel_Calculation_Functions::RETURNDATE_EXCEL 'E'
- */
- public static function getReturnDateType()
- {
- return self::$returnDateType;
- }
-
-
- /**
- * DUMMY
- *
- * @access public
- * @category Error Returns
- * @return string #Not Yet Implemented
- */
- public static function DUMMY()
- {
- return '#Not Yet Implemented';
- }
-
-
- /**
- * DIV0
- *
- * @access public
- * @category Error Returns
- * @return string #Not Yet Implemented
- */
- public static function DIV0()
- {
- return self::$errorCodes['divisionbyzero'];
- }
-
-
- /**
- * NA
- *
- * Excel Function:
- * =NA()
- *
- * Returns the error value #N/A
- * #N/A is the error value that means "no value is available."
- *
- * @access public
- * @category Logical Functions
- * @return string #N/A!
- */
- public static function NA()
- {
- return self::$errorCodes['na'];
- }
-
-
- /**
- * NaN
- *
- * Returns the error value #NUM!
- *
- * @access public
- * @category Error Returns
- * @return string #NUM!
- */
- public static function NaN()
- {
- return self::$errorCodes['num'];
- }
-
-
- /**
- * NAME
- *
- * Returns the error value #NAME?
- *
- * @access public
- * @category Error Returns
- * @return string #NAME?
- */
- public static function NAME()
- {
- return self::$errorCodes['name'];
- }
-
-
- /**
- * REF
- *
- * Returns the error value #REF!
- *
- * @access public
- * @category Error Returns
- * @return string #REF!
- */
- public static function REF()
- {
- return self::$errorCodes['reference'];
- }
-
-
- /**
- * NULL
- *
- * Returns the error value #NULL!
- *
- * @access public
- * @category Error Returns
- * @return string #NULL!
- */
- public static function NULL()
- {
- return self::$errorCodes['null'];
- }
-
-
- /**
- * VALUE
- *
- * Returns the error value #VALUE!
- *
- * @access public
- * @category Error Returns
- * @return string #VALUE!
- */
- public static function VALUE()
- {
- return self::$errorCodes['value'];
- }
-
-
- public static function isMatrixValue($idx)
- {
- return ((substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0));
- }
-
-
- public static function isValue($idx)
- {
- return (substr_count($idx, '.') == 0);
- }
-
-
- public static function isCellValue($idx)
- {
- return (substr_count($idx, '.') > 1);
- }
-
-
- public static function ifCondition($condition)
- {
- $condition = PHPExcel_Calculation_Functions::flattenSingleValue($condition);
- if (!isset($condition[0])) {
- $condition = '=""';
- }
- if (!in_array($condition[0], array('>', '<', '='))) {
- if (!is_numeric($condition)) {
- $condition = PHPExcel_Calculation::wrapResult(strtoupper($condition));
- }
- return '=' . $condition;
- } else {
- preg_match('/([<>=]+)(.*)/', $condition, $matches);
- list(, $operator, $operand) = $matches;
-
- if (!is_numeric($operand)) {
- $operand = str_replace('"', '""', $operand);
- $operand = PHPExcel_Calculation::wrapResult(strtoupper($operand));
- }
-
- return $operator.$operand;
- }
- }
-
- /**
- * ERROR_TYPE
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function ERROR_TYPE($value = '')
- {
- $value = self::flattenSingleValue($value);
-
- $i = 1;
- foreach (self::$errorCodes as $errorCode) {
- if ($value === $errorCode) {
- return $i;
- }
- ++$i;
- }
- return self::NA();
- }
-
-
- /**
- * IS_BLANK
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function IS_BLANK($value = null)
- {
- if (!is_null($value)) {
- $value = self::flattenSingleValue($value);
- }
-
- return is_null($value);
- }
-
-
- /**
- * IS_ERR
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function IS_ERR($value = '')
- {
- $value = self::flattenSingleValue($value);
-
- return self::IS_ERROR($value) && (!self::IS_NA($value));
- }
-
-
- /**
- * IS_ERROR
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function IS_ERROR($value = '')
- {
- $value = self::flattenSingleValue($value);
-
- if (!is_string($value)) {
- return false;
- }
- return in_array($value, array_values(self::$errorCodes));
- }
-
-
- /**
- * IS_NA
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function IS_NA($value = '')
- {
- $value = self::flattenSingleValue($value);
-
- return ($value === self::NA());
- }
-
-
- /**
- * IS_EVEN
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function IS_EVEN($value = null)
- {
- $value = self::flattenSingleValue($value);
-
- if ($value === null) {
- return self::NAME();
- } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
- return self::VALUE();
- }
-
- return ($value % 2 == 0);
- }
-
-
- /**
- * IS_ODD
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function IS_ODD($value = null)
- {
- $value = self::flattenSingleValue($value);
-
- if ($value === null) {
- return self::NAME();
- } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
- return self::VALUE();
- }
-
- return (abs($value) % 2 == 1);
- }
-
-
- /**
- * IS_NUMBER
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function IS_NUMBER($value = null)
- {
- $value = self::flattenSingleValue($value);
-
- if (is_string($value)) {
- return false;
- }
- return is_numeric($value);
- }
-
-
- /**
- * IS_LOGICAL
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function IS_LOGICAL($value = null)
- {
- $value = self::flattenSingleValue($value);
-
- return is_bool($value);
- }
-
-
- /**
- * IS_TEXT
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function IS_TEXT($value = null)
- {
- $value = self::flattenSingleValue($value);
-
- return (is_string($value) && !self::IS_ERROR($value));
- }
-
-
- /**
- * IS_NONTEXT
- *
- * @param mixed $value Value to check
- * @return boolean
- */
- public static function IS_NONTEXT($value = null)
- {
- return !self::IS_TEXT($value);
- }
-
-
- /**
- * VERSION
- *
- * @return string Version information
- */
- public static function VERSION()
- {
- return 'PHPExcel ##VERSION##, ##DATE##';
- }
-
-
- /**
- * N
- *
- * Returns a value converted to a number
- *
- * @param value The value you want converted
- * @return number N converts values listed in the following table
- * If value is or refers to N returns
- * A number That number
- * A date The serial number of that date
- * TRUE 1
- * FALSE 0
- * An error value The error value
- * Anything else 0
- */
- public static function N($value = null)
- {
- while (is_array($value)) {
- $value = array_shift($value);
- }
-
- switch (gettype($value)) {
- case 'double':
- case 'float':
- case 'integer':
- return $value;
- case 'boolean':
- return (integer) $value;
- case 'string':
- // Errors
- if ((strlen($value) > 0) && ($value[0] == '#')) {
- return $value;
- }
- break;
- }
- return 0;
- }
-
-
- /**
- * TYPE
- *
- * Returns a number that identifies the type of a value
- *
- * @param value The value you want tested
- * @return number N converts values listed in the following table
- * If value is or refers to N returns
- * A number 1
- * Text 2
- * Logical Value 4
- * An error value 16
- * Array or Matrix 64
- */
- public static function TYPE($value = null)
- {
- $value = self::flattenArrayIndexed($value);
- if (is_array($value) && (count($value) > 1)) {
- end($value);
- $a = key($value);
- // Range of cells is an error
- if (self::isCellValue($a)) {
- return 16;
- // Test for Matrix
- } elseif (self::isMatrixValue($a)) {
- return 64;
- }
- } elseif (empty($value)) {
- // Empty Cell
- return 1;
- }
- $value = self::flattenSingleValue($value);
-
- if (($value === null) || (is_float($value)) || (is_int($value))) {
- return 1;
- } elseif (is_bool($value)) {
- return 4;
- } elseif (is_array($value)) {
- return 64;
- } elseif (is_string($value)) {
- // Errors
- if ((strlen($value) > 0) && ($value[0] == '#')) {
- return 16;
- }
- return 2;
- }
- return 0;
- }
-
-
- /**
- * Convert a multi-dimensional array to a simple 1-dimensional array
- *
- * @param array $array Array to be flattened
- * @return array Flattened array
- */
- public static function flattenArray($array)
- {
- if (!is_array($array)) {
- return (array) $array;
- }
-
- $arrayValues = array();
- foreach ($array as $value) {
- if (is_array($value)) {
- foreach ($value as $val) {
- if (is_array($val)) {
- foreach ($val as $v) {
- $arrayValues[] = $v;
- }
- } else {
- $arrayValues[] = $val;
- }
- }
- } else {
- $arrayValues[] = $value;
- }
- }
-
- return $arrayValues;
- }
-
-
- /**
- * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing
- *
- * @param array $array Array to be flattened
- * @return array Flattened array
- */
- public static function flattenArrayIndexed($array)
- {
- if (!is_array($array)) {
- return (array) $array;
- }
-
- $arrayValues = array();
- foreach ($array as $k1 => $value) {
- if (is_array($value)) {
- foreach ($value as $k2 => $val) {
- if (is_array($val)) {
- foreach ($val as $k3 => $v) {
- $arrayValues[$k1.'.'.$k2.'.'.$k3] = $v;
- }
- } else {
- $arrayValues[$k1.'.'.$k2] = $val;
- }
- }
- } else {
- $arrayValues[$k1] = $value;
- }
- }
-
- return $arrayValues;
- }
-
-
- /**
- * Convert an array to a single scalar value by extracting the first element
- *
- * @param mixed $value Array or scalar value
- * @return mixed
- */
- public static function flattenSingleValue($value = '')
- {
- while (is_array($value)) {
- $value = array_pop($value);
- }
-
- return $value;
- }
- }
-
-
- //
- // There are a few mathematical functions that aren't available on all versions of PHP for all platforms
- // These functions aren't available in Windows implementations of PHP prior to version 5.3.0
- // So we test if they do exist for this version of PHP/operating platform; and if not we create them
- //
- if (!function_exists('acosh')) {
- function acosh($x)
- {
- return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2));
- } // function acosh()
- }
-
- if (!function_exists('asinh')) {
- function asinh($x)
- {
- return log($x + sqrt(1 + $x * $x));
- } // function asinh()
- }
-
- if (!function_exists('atanh')) {
- function atanh($x)
- {
- return (log(1 + $x) - log(1 - $x)) / 2;
- } // function atanh()
- }
-
-
- //
- // Strangely, PHP doesn't have a mb_str_replace multibyte function
- // As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set
- //
- if ((!function_exists('mb_str_replace')) &&
- (function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos'))) {
- function mb_str_replace($search, $replace, $subject)
- {
- if (is_array($subject)) {
- $ret = array();
- foreach ($subject as $key => $val) {
- $ret[$key] = mb_str_replace($search, $replace, $val);
- }
- return $ret;
- }
-
- foreach ((array) $search as $key => $s) {
- if ($s == '' && $s !== 0) {
- continue;
- }
- $r = !is_array($replace) ? $replace : (array_key_exists($key, $replace) ? $replace[$key] : '');
- $pos = mb_strpos($subject, $s, 0, 'UTF-8');
- while ($pos !== false) {
- $subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), 65535, 'UTF-8');
- $pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8');
- }
- }
- return $subject;
- }
- }
|