PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/framework/lib/classes/PHPExcel/Calculation/Functions.php

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