Completed
Push — develop ( 268fc1...a06731 )
by Adrien
23:59
created

Functions   D

Complexity

Total Complexity 92

Size/Duplication

Total Lines 605
Duplicated Lines 3.97 %

Coupling/Cohesion

Components 3
Dependencies 1

Test Coverage

Coverage 93.6%

Importance

Changes 0
Metric Value
dl 24
loc 605
ccs 161
cts 172
cp 0.936
rs 4.8519
c 0
b 0
f 0
wmc 92
lcom 3
cbo 1

32 Methods

Rating   Name   Duplication   Size   Complexity  
A setCompatibilityMode() 0 13 4
A getCompatibilityMode() 0 4 1
A setReturnDateType() 0 13 4
A getReturnDateType() 0 4 1
A DUMMY() 0 4 1
A DIV0() 0 4 1
A NA() 0 4 1
A NAN() 0 4 1
A NAME() 0 4 1
A REF() 0 4 1
A null() 0 4 1
A VALUE() 0 4 1
A isMatrixValue() 0 4 2
A isValue() 0 4 1
A isCellValue() 0 4 1
B ifCondition() 0 24 5
A errorType() 0 14 3
A isBlank() 0 8 2
A isErr() 0 6 2
A isError() 0 10 2
A isNa() 0 6 1
B isEven() 12 12 5
B isOdd() 12 12 5
A isNumber() 0 10 2
A isLogical() 0 6 1
A isText() 0 6 2
A isNonText() 0 4 1
C n() 0 23 9
C TYPE() 0 36 14
C flattenArray() 0 25 7
C flattenArrayIndexed() 0 25 7
A flattenSingleValue() 0 8 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Functions often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Functions, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation;
4
5
/* MAX_VALUE */
6 61
define('MAX_VALUE', 1.2e308);
7
8
/* 2 / PI */
9 61
define('M_2DIVPI', 0.63661977236758134307553505349006);
10
11
/* MAX_ITERATIONS */
12 61
define('MAX_ITERATIONS', 256);
13
14
/* PRECISION */
15 61
define('PRECISION', 8.88E-016);
16
17
/**
18
 * Copyright (c) 2006 - 2016 PhpSpreadsheet
19
 *
20
 * This library is free software; you can redistribute it and/or
21
 * modify it under the terms of the GNU Lesser General Public
22
 * License as published by the Free Software Foundation; either
23
 * version 2.1 of the License, or (at your option) any later version.
24
 *
25
 * This library is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28
 * Lesser General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Lesser General Public
31
 * License along with this library; if not, write to the Free Software
32
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33
 *
34
 * @category    PhpSpreadsheet
35
 * @copyright   Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
36
 * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
37
 */
38
class Functions
39
{
40
    /** constants */
41
    const COMPATIBILITY_EXCEL = 'Excel';
42
    const COMPATIBILITY_GNUMERIC = 'Gnumeric';
43
    const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
44
45
    const RETURNDATE_PHP_NUMERIC = 'P';
46
    const RETURNDATE_PHP_OBJECT = 'O';
47
    const RETURNDATE_EXCEL = 'E';
48
49
    /**
50
     * Compatibility mode to use for error checking and responses
51
     *
52
     * @var string
53
     */
54
    protected static $compatibilityMode = self::COMPATIBILITY_EXCEL;
55
56
    /**
57
     * Data Type to use when returning date values
58
     *
59
     * @var string
60
     */
61
    protected static $returnDateType = self::RETURNDATE_EXCEL;
62
63
    /**
64
     * List of error codes
65
     *
66
     * @var array
67
     */
68
    protected static $errorCodes = [
69
        'null' => '#NULL!',
70
        'divisionbyzero' => '#DIV/0!',
71
        'value' => '#VALUE!',
72
        'reference' => '#REF!',
73
        'name' => '#NAME?',
74
        'num' => '#NUM!',
75
        'na' => '#N/A',
76
        'gettingdata' => '#GETTING_DATA',
77
    ];
78
79
    /**
80
     * Set the Compatibility Mode
81
     *
82
     * @category Function Configuration
83
     * @param     string $compatibilityMode Compatibility Mode
84
     *                                                Permitted values are:
85
     *                                                    Functions::COMPATIBILITY_EXCEL            'Excel'
86
     *                                                    Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
87
     *                                                    Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
88
     * @return     bool    (Success or Failure)
89
     */
90 3588
    public static function setCompatibilityMode($compatibilityMode)
91
    {
92 3588
        if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
93 52
            ($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
94 3588
            ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)
95
        ) {
96 3588
            self::$compatibilityMode = $compatibilityMode;
97
98 3588
            return true;
99
        }
100
101
        return false;
102
    }
103
104
    /**
105
     * Return the current Compatibility Mode
106
     *
107
     * @category Function Configuration
108
     * @return     string        Compatibility Mode
109
     *                            Possible Return values are:
110
     *                                Functions::COMPATIBILITY_EXCEL            'Excel'
111
     *                                Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
112
     *                                Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
113
     */
114 669
    public static function getCompatibilityMode()
115
    {
116 669
        return self::$compatibilityMode;
117
    }
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
     * @category Function Configuration
123
     * @param     string $returnDateType Return Date Format
124
     *                                                Permitted values are:
125
     *                                                    Functions::RETURNDATE_PHP_NUMERIC        'P'
126
     *                                                    Functions::RETURNDATE_PHP_OBJECT        'O'
127
     *                                                    Functions::RETURNDATE_EXCEL            'E'
128
     * @return     bool                            Success or failure
129
     */
130 431
    public static function setReturnDateType($returnDateType)
131
    {
132 431
        if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
133 431
            ($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
134 431
            ($returnDateType == self::RETURNDATE_EXCEL)
135
        ) {
136 431
            self::$returnDateType = $returnDateType;
137
138 431
            return true;
139
        }
140
141
        return false;
142
    }
143
144
    /**
145
     * Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
146
     *
147
     * @category Function Configuration
148
     * @return     string        Return Date Format
149
     *                            Possible Return values are:
150
     *                                Functions::RETURNDATE_PHP_NUMERIC        'P'
151
     *                                Functions::RETURNDATE_PHP_OBJECT        'O'
152
     *                                Functions::RETURNDATE_EXCEL            'E'
153
     */
154 594
    public static function getReturnDateType()
155
    {
156 594
        return self::$returnDateType;
157
    }
158
159
    /**
160
     * DUMMY
161
     *
162
     * @category Error Returns
163
     * @return    string    #Not Yet Implemented
164
     */
165 1
    public static function DUMMY()
166
    {
167 1
        return '#Not Yet Implemented';
168
    }
169
170
    /**
171
     * DIV0
172
     *
173
     * @category Error Returns
174
     * @return    string    #Not Yet Implemented
175
     */
176 11
    public static function DIV0()
177
    {
178 11
        return self::$errorCodes['divisionbyzero'];
179
    }
180
181
    /**
182
     * NA
183
     *
184
     * Excel Function:
185
     *        =NA()
186
     *
187
     * Returns the error value #N/A
188
     *        #N/A is the error value that means "no value is available."
189
     *
190
     * @category Logical Functions
191
     * @return    string    #N/A!
192
     */
193 38
    public static function NA()
194
    {
195 38
        return self::$errorCodes['na'];
196
    }
197
198
    /**
199
     * NaN
200
     *
201
     * Returns the error value #NUM!
202
     *
203
     * @category Error Returns
204
     * @return    string    #NUM!
205
     */
206 307
    public static function NAN()
207
    {
208 307
        return self::$errorCodes['num'];
209
    }
210
211
    /**
212
     * NAME
213
     *
214
     * Returns the error value #NAME?
215
     *
216
     * @category Error Returns
217
     * @return    string    #NAME?
218
     */
219 5
    public static function NAME()
220
    {
221 5
        return self::$errorCodes['name'];
222
    }
223
224
    /**
225
     * REF
226
     *
227
     * Returns the error value #REF!
228
     *
229
     * @category Error Returns
230
     * @return    string    #REF!
231
     */
232 3
    public static function REF()
233
    {
234 3
        return self::$errorCodes['reference'];
235
    }
236
237
    /**
238
     * NULL
239
     *
240
     * Returns the error value #NULL!
241
     *
242
     * @category Error Returns
243
     * @return    string    #NULL!
244
     */
245 1
    public static function null()
246
    {
247 1
        return self::$errorCodes['null'];
248
    }
249
250
    /**
251
     * VALUE
252
     *
253
     * Returns the error value #VALUE!
254
     *
255
     * @category Error Returns
256
     * @return    string    #VALUE!
257
     */
258 179
    public static function VALUE()
259
    {
260 179
        return self::$errorCodes['value'];
261
    }
262
263 4
    public static function isMatrixValue($idx)
264
    {
265 4
        return (substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0);
266
    }
267
268 1
    public static function isValue($idx)
269
    {
270 1
        return substr_count($idx, '.') == 0;
271
    }
272
273 5
    public static function isCellValue($idx)
274
    {
275 5
        return substr_count($idx, '.') > 1;
276
    }
277
278 5
    public static function ifCondition($condition)
279
    {
280 5
        $condition = self::flattenSingleValue($condition);
281 5
        if (!isset($condition{0})) {
282
            $condition = '=""';
283
        }
284 5
        if (!in_array($condition{0}, ['>', '<', '='])) {
285
            if (!is_numeric($condition)) {
286
                $condition = \PhpOffice\PhpSpreadsheet\Calculation::wrapResult(strtoupper($condition));
287
            }
288
289
            return '=' . $condition;
290
        } else {
291 5
            preg_match('/([<>=]+)(.*)/', $condition, $matches);
292 5
            list(, $operator, $operand) = $matches;
293
294 5
            if (!is_numeric($operand)) {
295 4
                $operand = str_replace('"', '""', $operand);
296 4
                $operand = \PhpOffice\PhpSpreadsheet\Calculation::wrapResult(strtoupper($operand));
297
            }
298
299 5
            return $operator . $operand;
300
        }
301
    }
302
303
    /**
304
     * ERROR_TYPE
305
     *
306
     * @param    mixed $value Value to check
307
     * @return    bool
308
     */
309 14
    public static function errorType($value = '')
310
    {
311 14
        $value = self::flattenSingleValue($value);
312
313 14
        $i = 1;
314 14
        foreach (self::$errorCodes as $errorCode) {
315 14
            if ($value === $errorCode) {
316 7
                return $i;
317
            }
318 13
            ++$i;
319
        }
320
321 7
        return self::NA();
322
    }
323
324
    /**
325
     * IS_BLANK
326
     *
327
     * @param    mixed $value Value to check
328
     * @return    bool
329
     */
330 16
    public static function isBlank($value = null)
331
    {
332 16
        if (!is_null($value)) {
333 14
            $value = self::flattenSingleValue($value);
334
        }
335
336 16
        return is_null($value);
337
    }
338
339
    /**
340
     * IS_ERR
341
     *
342
     * @param    mixed $value Value to check
343
     * @return    bool
344
     */
345 16
    public static function isErr($value = '')
346
    {
347 16
        $value = self::flattenSingleValue($value);
348
349 16
        return self::isError($value) && (!self::isNa(($value)));
350
    }
351
352
    /**
353
     * IS_ERROR
354
     *
355
     * @param    mixed $value Value to check
356
     * @return    bool
357
     */
358 56
    public static function isError($value = '')
359
    {
360 56
        $value = self::flattenSingleValue($value);
361
362 56
        if (!is_string($value)) {
363 16
            return false;
364
        }
365
366 40
        return in_array($value, array_values(self::$errorCodes));
367
    }
368
369
    /**
370
     * IS_NA
371
     *
372
     * @param    mixed $value Value to check
373
     * @return    bool
374
     */
375 18
    public static function isNa($value = '')
376
    {
377 18
        $value = self::flattenSingleValue($value);
378
379 18
        return $value === self::NA();
380
    }
381
382
    /**
383
     * IS_EVEN
384
     *
385
     * @param    mixed $value Value to check
386
     * @return    string|bool
387
     */
388 20 View Code Duplication
    public static function isEven($value = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
389
    {
390 20
        $value = self::flattenSingleValue($value);
391
392 20
        if ($value === null) {
393 2
            return self::NAME();
394 18
        } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
395 7
            return self::VALUE();
396
        }
397
398 11
        return $value % 2 == 0;
399
    }
400
401
    /**
402
     * IS_ODD
403
     *
404
     * @param    mixed $value Value to check
405
     * @return    string|bool
406
     */
407 20 View Code Duplication
    public static function isOdd($value = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
408
    {
409 20
        $value = self::flattenSingleValue($value);
410
411 20
        if ($value === null) {
412 2
            return self::NAME();
413 18
        } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
414 7
            return self::VALUE();
415
        }
416
417 11
        return abs($value) % 2 == 1;
418
    }
419
420
    /**
421
     * IS_NUMBER
422
     *
423
     * @param    mixed $value Value to check
424
     * @return    bool
425
     */
426 16
    public static function isNumber($value = null)
427
    {
428 16
        $value = self::flattenSingleValue($value);
429
430 16
        if (is_string($value)) {
431 8
            return false;
432
        }
433
434 8
        return is_numeric($value);
435
    }
436
437
    /**
438
     * IS_LOGICAL
439
     *
440
     * @param    mixed $value Value to check
441
     * @return    bool
442
     */
443 16
    public static function isLogical($value = null)
444
    {
445 16
        $value = self::flattenSingleValue($value);
446
447 16
        return is_bool($value);
448
    }
449
450
    /**
451
     * IS_TEXT
452
     *
453
     * @param    mixed $value Value to check
454
     * @return    bool
455
     */
456 32
    public static function isText($value = null)
457
    {
458 32
        $value = self::flattenSingleValue($value);
459
460 32
        return is_string($value) && !self::isError($value);
461
    }
462
463
    /**
464
     * IS_NONTEXT
465
     *
466
     * @param    mixed $value Value to check
467
     * @return    bool
468
     */
469 16
    public static function isNonText($value = null)
470
    {
471 16
        return !self::isText($value);
472
    }
473
474
    /**
475
     * N
476
     *
477
     * Returns a value converted to a number
478
     *
479
     * @param    value        The value you want converted
480
     * @return    number        N converts values listed in the following table
481
     *        If value is or refers to N returns
482
     *        A number            That number
483
     *        A date                The serial number of that date
484
     *        TRUE                1
485
     *        FALSE                0
486
     *        An error value        The error value
487
     *        Anything else        0
488
     */
489 20
    public static function n($value = null)
490
    {
491 20
        while (is_array($value)) {
492 9
            $value = array_shift($value);
493
        }
494
495 20
        switch (gettype($value)) {
496 20
            case 'double':
497 19
            case 'float':
498 19
            case 'integer':
499 8
                return $value;
500 12
            case 'boolean':
501 1
                return (integer) $value;
502 11
            case 'string':
503
                //    Errors
504 8
                if ((strlen($value) > 0) && ($value{0} == '#')) {
505 2
                    return $value;
506
                }
507 6
                break;
508
        }
509
510 9
        return 0;
511
    }
512
513
    /**
514
     * TYPE
515
     *
516
     * Returns a number that identifies the type of a value
517
     *
518
     * @param    value        The value you want tested
519
     * @return    number        N converts values listed in the following table
520
     *        If value is or refers to N returns
521
     *        A number            1
522
     *        Text                2
523
     *        Logical Value        4
524
     *        An error value        16
525
     *        Array or Matrix        64
526
     */
527 16
    public static function TYPE($value = null)
528
    {
529 16
        $value = self::flattenArrayIndexed($value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type null; however, PhpOffice\PhpSpreadsheet...::flattenArrayIndexed() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
530 16
        if (is_array($value) && (count($value) > 1)) {
531 3
            end($value);
532 3
            $a = key($value);
533
            //    Range of cells is an error
534 3
            if (self::isCellValue($a)) {
535
                return 16;
536
                //    Test for Matrix
537 3
            } elseif (self::isMatrixValue($a)) {
538 3
                return 64;
539
            }
540
        } elseif (empty($value)) {
541
            //    Empty Cell
542 2
            return 1;
543
        }
544 11
        $value = self::flattenSingleValue($value);
545
546 11
        if (($value === null) || (is_float($value)) || (is_int($value))) {
547 4
            return 1;
548 7
        } elseif (is_bool($value)) {
549 1
            return 4;
550 6
        } elseif (is_array($value)) {
551
            return 64;
552 6
        } elseif (is_string($value)) {
553
            //    Errors
554 6
            if ((strlen($value) > 0) && ($value{0} == '#')) {
555 2
                return 16;
556
            }
557
558 4
            return 2;
559
        }
560
561
        return 0;
562
    }
563
564
    /**
565
     * Convert a multi-dimensional array to a simple 1-dimensional array
566
     *
567
     * @param    array $array Array to be flattened
568
     * @return    array    Flattened array
569
     */
570 265
    public static function flattenArray($array)
571
    {
572 265
        if (!is_array($array)) {
573
            return (array) $array;
574
        }
575
576 265
        $arrayValues = [];
577 265
        foreach ($array as $value) {
578 263
            if (is_array($value)) {
579 53
                foreach ($value as $val) {
580 53
                    if (is_array($val)) {
581 23
                        foreach ($val as $v) {
582 23
                            $arrayValues[] = $v;
583
                        }
584
                    } else {
585 53
                        $arrayValues[] = $val;
586
                    }
587
                }
588
            } else {
589 263
                $arrayValues[] = $value;
590
            }
591
        }
592
593 265
        return $arrayValues;
594
    }
595
596
    /**
597
     * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing
598
     *
599
     * @param    array $array Array to be flattened
600
     * @return    array    Flattened array
601
     */
602 19
    public static function flattenArrayIndexed($array)
603
    {
604 19
        if (!is_array($array)) {
605 11
            return (array) $array;
606
        }
607
608 8
        $arrayValues = [];
609 8
        foreach ($array as $k1 => $value) {
610 8
            if (is_array($value)) {
611 5
                foreach ($value as $k2 => $val) {
612 5
                    if (is_array($val)) {
613 3
                        foreach ($val as $k3 => $v) {
614 3
                            $arrayValues[$k1 . '.' . $k2 . '.' . $k3] = $v;
615
                        }
616
                    } else {
617 5
                        $arrayValues[$k1 . '.' . $k2] = $val;
618
                    }
619
                }
620
            } else {
621 8
                $arrayValues[$k1] = $value;
622
            }
623
        }
624
625 8
        return $arrayValues;
626
    }
627
628
    /**
629
     * Convert an array to a single scalar value by extracting the first element
630
     *
631
     * @param    mixed $value Array or scalar value
632
     * @return    mixed
633
     */
634 3100
    public static function flattenSingleValue($value = '')
635
    {
636 3100
        while (is_array($value)) {
637 32
            $value = array_pop($value);
638
        }
639
640 3100
        return $value;
641
    }
642
}
643
644
//
645
//    There are a few mathematical functions that aren't available on all versions of PHP for all platforms
646
//    These functions aren't available in Windows implementations of PHP prior to version 5.3.0
647
//    So we test if they do exist for this version of PHP/operating platform; and if not we create them
648
//
649 61
if (!function_exists('acosh')) {
650
    function acosh($x)
651
    {
652
        return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2));
653
    }    //    function acosh()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
654
}
655
656 61
if (!function_exists('asinh')) {
657
    function asinh($x)
658
    {
659
        return log($x + sqrt(1 + $x * $x));
660
    }    //    function asinh()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
661
}
662
663 61
if (!function_exists('atanh')) {
664
    function atanh($x)
665
    {
666
        return (log(1 + $x) - log(1 - $x)) / 2;
667
    }    //    function atanh()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
668
}
669
670
//
671
//    Strangely, PHP doesn't have a mb_str_replace multibyte function
672
//    As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set
673
//
674 61
if ((!function_exists('mb_str_replace')) &&
675 61
    (function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos'))
676
) {
677
    function mb_str_replace($search, $replace, $subject)
678
    {
679
        if (is_array($subject)) {
680
            $ret = [];
681
            foreach ($subject as $key => $val) {
682
                $ret[$key] = mb_str_replace($search, $replace, $val);
683
            }
684
685
            return $ret;
686
        }
687
688
        foreach ((array) $search as $key => $s) {
689
            if ($s == '' && $s !== 0) {
690
                continue;
691
            }
692
            $r = !is_array($replace) ? $replace : (isset($replace[$key]) ? $replace[$key] : '');
693
            $pos = mb_strpos($subject, $s, 0, 'UTF-8');
694
            while ($pos !== false) {
695
                $subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), null, 'UTF-8');
696
                $pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8');
697
            }
698
        }
699
700
        return $subject;
701
    }
702
}
703