123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645 |
- <?php
- namespace PhpOffice\PhpSpreadsheet\Calculation;
- class Functions
- {
- const PRECISION = 8.88E-016;
- /**
- * 2 / PI.
- */
- const M_2DIVPI = 0.63661977236758134307553505349006;
- /** 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.
- *
- * @var string
- */
- protected static $compatibilityMode = self::COMPATIBILITY_EXCEL;
- /**
- * Data Type to use when returning date values.
- *
- * @var string
- */
- protected static $returnDateType = self::RETURNDATE_EXCEL;
- /**
- * List of error codes.
- *
- * @var array
- */
- protected static $errorCodes = [
- 'null' => '#NULL!',
- 'divisionbyzero' => '#DIV/0!',
- 'value' => '#VALUE!',
- 'reference' => '#REF!',
- 'name' => '#NAME?',
- 'num' => '#NUM!',
- 'na' => '#N/A',
- 'gettingdata' => '#GETTING_DATA',
- ];
- /**
- * Set the Compatibility Mode.
- *
- * @category Function Configuration
- *
- * @param string $compatibilityMode Compatibility Mode
- * Permitted values are:
- * Functions::COMPATIBILITY_EXCEL 'Excel'
- * Functions::COMPATIBILITY_GNUMERIC 'Gnumeric'
- * Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc'
- *
- * @return bool (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.
- *
- * @category Function Configuration
- *
- * @return string Compatibility Mode
- * Possible Return values are:
- * Functions::COMPATIBILITY_EXCEL 'Excel'
- * Functions::COMPATIBILITY_GNUMERIC 'Gnumeric'
- * 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).
- *
- * @category Function Configuration
- *
- * @param string $returnDateType Return Date Format
- * Permitted values are:
- * Functions::RETURNDATE_PHP_NUMERIC 'P'
- * Functions::RETURNDATE_PHP_OBJECT 'O'
- * Functions::RETURNDATE_EXCEL 'E'
- *
- * @return bool 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).
- *
- * @category Function Configuration
- *
- * @return string Return Date Format
- * Possible Return values are:
- * Functions::RETURNDATE_PHP_NUMERIC 'P'
- * Functions::RETURNDATE_PHP_OBJECT 'O'
- * Functions::RETURNDATE_EXCEL 'E'
- */
- public static function getReturnDateType()
- {
- return self::$returnDateType;
- }
- /**
- * DUMMY.
- *
- * @category Error Returns
- *
- * @return string #Not Yet Implemented
- */
- public static function DUMMY()
- {
- return '#Not Yet Implemented';
- }
- /**
- * DIV0.
- *
- * @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."
- *
- * @category Logical Functions
- *
- * @return string #N/A!
- */
- public static function NA()
- {
- return self::$errorCodes['na'];
- }
- /**
- * NaN.
- *
- * Returns the error value #NUM!
- *
- * @category Error Returns
- *
- * @return string #NUM!
- */
- public static function NAN()
- {
- return self::$errorCodes['num'];
- }
- /**
- * NAME.
- *
- * Returns the error value #NAME?
- *
- * @category Error Returns
- *
- * @return string #NAME?
- */
- public static function NAME()
- {
- return self::$errorCodes['name'];
- }
- /**
- * REF.
- *
- * Returns the error value #REF!
- *
- * @category Error Returns
- *
- * @return string #REF!
- */
- public static function REF()
- {
- return self::$errorCodes['reference'];
- }
- /**
- * NULL.
- *
- * Returns the error value #NULL!
- *
- * @category Error Returns
- *
- * @return string #NULL!
- */
- public static function null()
- {
- return self::$errorCodes['null'];
- }
- /**
- * VALUE.
- *
- * Returns the error value #VALUE!
- *
- * @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 = self::flattenSingleValue($condition);
- if (!isset($condition[0])) {
- $condition = '=""';
- }
- if (!in_array($condition[0], ['>', '<', '='])) {
- if (!is_numeric($condition)) {
- $condition = Calculation::wrapResult(strtoupper($condition));
- }
- return '=' . $condition;
- }
- preg_match('/([<>=]+)(.*)/', $condition, $matches);
- list(, $operator, $operand) = $matches;
- if (!is_numeric($operand)) {
- $operand = str_replace('"', '""', $operand);
- $operand = Calculation::wrapResult(strtoupper($operand));
- }
- return $operator . $operand;
- }
- /**
- * ERROR_TYPE.
- *
- * @param mixed $value Value to check
- *
- * @return bool
- */
- public static function errorType($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 bool
- */
- public static function isBlank($value = null)
- {
- if ($value !== null) {
- $value = self::flattenSingleValue($value);
- }
- return $value === null;
- }
- /**
- * IS_ERR.
- *
- * @param mixed $value Value to check
- *
- * @return bool
- */
- public static function isErr($value = '')
- {
- $value = self::flattenSingleValue($value);
- return self::isError($value) && (!self::isNa(($value)));
- }
- /**
- * IS_ERROR.
- *
- * @param mixed $value Value to check
- *
- * @return bool
- */
- public static function isError($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 bool
- */
- public static function isNa($value = '')
- {
- $value = self::flattenSingleValue($value);
- return $value === self::NA();
- }
- /**
- * IS_EVEN.
- *
- * @param mixed $value Value to check
- *
- * @return bool|string
- */
- public static function isEven($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 bool|string
- */
- public static function isOdd($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 bool
- */
- public static function isNumber($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 bool
- */
- public static function isLogical($value = null)
- {
- $value = self::flattenSingleValue($value);
- return is_bool($value);
- }
- /**
- * IS_TEXT.
- *
- * @param mixed $value Value to check
- *
- * @return bool
- */
- public static function isText($value = null)
- {
- $value = self::flattenSingleValue($value);
- return is_string($value) && !self::isError($value);
- }
- /**
- * IS_NONTEXT.
- *
- * @param mixed $value Value to check
- *
- * @return bool
- */
- public static function isNonText($value = null)
- {
- return !self::isText($value);
- }
- /**
- * N.
- *
- * Returns a value converted to a number
- *
- * @param null|mixed $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 (int) $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 null|mixed $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 = [];
- 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 = [];
- 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;
- }
- }
|