Passed
Push — develop ( 043327...eb3189 )
by Adrien
24:31
created

TextData::EXACT()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation;
4
5
use PhpOffice\PhpSpreadsheet\Shared\Date;
6
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
7
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
8
9
class TextData
10
{
11
    private static $invalidChars;
12
13 15
    private static function unicodeToOrd($character)
14
    {
15 15
        return unpack('V', iconv('UTF-8', 'UCS-4LE', $character))[1];
16
    }
17
18
    /**
19
     * CHARACTER.
20
     *
21
     * @param string $character Value
22
     *
23
     * @return string
24
     */
25 11
    public static function CHARACTER($character)
26
    {
27 11
        $character = Functions::flattenSingleValue($character);
28
29 11
        if ((!is_numeric($character)) || ($character < 0)) {
30 2
            return Functions::VALUE();
31
        }
32
33 9
        if (function_exists('iconv')) {
34 9
            return iconv('UCS-4LE', 'UTF-8', pack('V', $character));
35
        }
36
37
        return mb_convert_encoding('&#' . (int) $character . ';', 'UTF-8', 'HTML-ENTITIES');
38
    }
39
40
    /**
41
     * TRIMNONPRINTABLE.
42
     *
43
     * @param mixed $stringValue Value to check
44
     *
45
     * @return string
46
     */
47 5
    public static function TRIMNONPRINTABLE($stringValue = '')
48
    {
49 5
        $stringValue = Functions::flattenSingleValue($stringValue);
50
51 5
        if (is_bool($stringValue)) {
52 1
            return ($stringValue) ? Calculation::getTRUE() : Calculation::getFALSE();
53
        }
54
55 4
        if (self::$invalidChars == null) {
56 1
            self::$invalidChars = range(chr(0), chr(31));
57
        }
58
59 4
        if (is_string($stringValue) || is_numeric($stringValue)) {
60 3
            return str_replace(self::$invalidChars, '', trim($stringValue, "\x00..\x1F"));
61
        }
62
63 1
        return null;
64
    }
65
66
    /**
67
     * TRIMSPACES.
68
     *
69
     * @param mixed $stringValue Value to check
70
     *
71
     * @return string
72
     */
73 7
    public static function TRIMSPACES($stringValue = '')
74
    {
75 7
        $stringValue = Functions::flattenSingleValue($stringValue);
76 7
        if (is_bool($stringValue)) {
77 1
            return ($stringValue) ? Calculation::getTRUE() : Calculation::getFALSE();
78
        }
79
80 6
        if (is_string($stringValue) || is_numeric($stringValue)) {
81 5
            return trim(preg_replace('/ +/', ' ', trim($stringValue, ' ')), ' ');
82
        }
83
84 1
        return null;
85
    }
86
87
    /**
88
     * ASCIICODE.
89
     *
90
     * @param string $characters Value
91
     *
92
     * @return int
93
     */
94 17
    public static function ASCIICODE($characters)
95
    {
96 17
        if (($characters === null) || ($characters === '')) {
97 2
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type integer.
Loading history...
98
        }
99 15
        $characters = Functions::flattenSingleValue($characters);
100 15
        if (is_bool($characters)) {
101 1
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
102
                $characters = (int) $characters;
103
            } else {
104 1
                $characters = ($characters) ? Calculation::getTRUE() : Calculation::getFALSE();
105
            }
106
        }
107
108 15
        $character = $characters;
109 15
        if (mb_strlen($characters, 'UTF-8') > 1) {
110 9
            $character = mb_substr($characters, 0, 1, 'UTF-8');
111
        }
112
113 15
        return self::unicodeToOrd($character);
114
    }
115
116
    /**
117
     * CONCATENATE.
118
     *
119
     * @return string
120
     */
121 4
    public static function CONCATENATE(...$args)
122
    {
123 4
        $returnValue = '';
124
125
        // Loop through arguments
126 4
        $aArgs = Functions::flattenArray($args);
127 4
        foreach ($aArgs as $arg) {
128 4
            if (is_bool($arg)) {
129 2
                if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
130 1
                    $arg = (int) $arg;
131
                } else {
132 1
                    $arg = ($arg) ? Calculation::getTRUE() : Calculation::getFALSE();
133
                }
134
            }
135 4
            $returnValue .= $arg;
136
        }
137
138 4
        return $returnValue;
139
    }
140
141
    /**
142
     * DOLLAR.
143
     *
144
     * This function converts a number to text using currency format, with the decimals rounded to the specified place.
145
     * The format used is $#,##0.00_);($#,##0.00)..
146
     *
147
     * @param float $value The value to format
148
     * @param int $decimals The number of digits to display to the right of the decimal point.
149
     *                                    If decimals is negative, number is rounded to the left of the decimal point.
150
     *                                    If you omit decimals, it is assumed to be 2
151
     *
152
     * @return string
153
     */
154 6
    public static function DOLLAR($value = 0, $decimals = 2)
155
    {
156 6
        $value = Functions::flattenSingleValue($value);
157 6
        $decimals = $decimals === null ? 0 : Functions::flattenSingleValue($decimals);
0 ignored issues
show
introduced by
The condition $decimals === null is always false.
Loading history...
158
159
        // Validate parameters
160 6
        if (!is_numeric($value) || !is_numeric($decimals)) {
161 2
            return Functions::NAN();
162
        }
163 4
        $decimals = floor($decimals);
164
165 4
        $mask = '$#,##0';
166 4
        if ($decimals > 0) {
167 2
            $mask .= '.' . str_repeat('0', $decimals);
0 ignored issues
show
Bug introduced by
$decimals of type double is incompatible with the type integer expected by parameter $multiplier of str_repeat(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

167
            $mask .= '.' . str_repeat('0', /** @scrutinizer ignore-type */ $decimals);
Loading history...
168
        } else {
169 2
            $round = pow(10, abs($decimals));
170 2
            if ($value < 0) {
171
                $round = 0 - $round;
172
            }
173 2
            $value = MathTrig::MROUND($value, $round);
174
        }
175
176 4
        return NumberFormat::toFormattedString($value, $mask);
177
    }
178
179
    /**
180
     * SEARCHSENSITIVE.
181
     *
182
     * @param string $needle The string to look for
183
     * @param string $haystack The string in which to look
184
     * @param int $offset Offset within $haystack
185
     *
186
     * @return string
187
     */
188 13
    public static function SEARCHSENSITIVE($needle, $haystack, $offset = 1)
189
    {
190 13
        $needle = Functions::flattenSingleValue($needle);
191 13
        $haystack = Functions::flattenSingleValue($haystack);
192 13
        $offset = Functions::flattenSingleValue($offset);
193
194 13
        if (!is_bool($needle)) {
195 13
            if (is_bool($haystack)) {
196 2
                $haystack = ($haystack) ? Calculation::getTRUE() : Calculation::getFALSE();
197
            }
198
199 13
            if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) {
200 13
                if (StringHelper::countCharacters($needle) == 0) {
201 2
                    return $offset;
202
                }
203
204 11
                $pos = mb_strpos($haystack, $needle, --$offset, 'UTF-8');
205 11
                if ($pos !== false) {
206 9
                    return ++$pos;
207
                }
208
            }
209
        }
210
211 2
        return Functions::VALUE();
212
    }
213
214
    /**
215
     * SEARCHINSENSITIVE.
216
     *
217
     * @param string $needle The string to look for
218
     * @param string $haystack The string in which to look
219
     * @param int $offset Offset within $haystack
220
     *
221
     * @return string
222
     */
223 11
    public static function SEARCHINSENSITIVE($needle, $haystack, $offset = 1)
224
    {
225 11
        $needle = Functions::flattenSingleValue($needle);
226 11
        $haystack = Functions::flattenSingleValue($haystack);
227 11
        $offset = Functions::flattenSingleValue($offset);
228
229 11
        if (!is_bool($needle)) {
230 11
            if (is_bool($haystack)) {
231 2
                $haystack = ($haystack) ? Calculation::getTRUE() : Calculation::getFALSE();
232
            }
233
234 11
            if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) {
235 11
                if (StringHelper::countCharacters($needle) == 0) {
236
                    return $offset;
237
                }
238
239 11
                $pos = mb_stripos($haystack, $needle, --$offset, 'UTF-8');
240 11
                if ($pos !== false) {
241 9
                    return ++$pos;
242
                }
243
            }
244
        }
245
246 2
        return Functions::VALUE();
247
    }
248
249
    /**
250
     * FIXEDFORMAT.
251
     *
252
     * @param mixed $value Value to check
253
     * @param int $decimals
254
     * @param bool $no_commas
255
     *
256
     * @return string
257
     */
258 5
    public static function FIXEDFORMAT($value, $decimals = 2, $no_commas = false)
259
    {
260 5
        $value = Functions::flattenSingleValue($value);
261 5
        $decimals = Functions::flattenSingleValue($decimals);
262 5
        $no_commas = Functions::flattenSingleValue($no_commas);
263
264
        // Validate parameters
265 5
        if (!is_numeric($value) || !is_numeric($decimals)) {
266 2
            return Functions::NAN();
267
        }
268 3
        $decimals = floor($decimals);
269
270 3
        $valueResult = round($value, $decimals);
0 ignored issues
show
Bug introduced by
$decimals of type double is incompatible with the type integer expected by parameter $precision of round(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

270
        $valueResult = round($value, /** @scrutinizer ignore-type */ $decimals);
Loading history...
271 3
        if ($decimals < 0) {
272
            $decimals = 0;
273
        }
274 3
        if (!$no_commas) {
275 1
            $valueResult = number_format($valueResult, $decimals);
1 ignored issue
show
Bug introduced by
It seems like $decimals can also be of type double; however, parameter $decimals of number_format() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

275
            $valueResult = number_format($valueResult, /** @scrutinizer ignore-type */ $decimals);
Loading history...
276
        }
277
278 3
        return (string) $valueResult;
279
    }
280
281
    /**
282
     * LEFT.
283
     *
284
     * @param string $value Value
285
     * @param int $chars Number of characters
286
     *
287
     * @return string
288
     */
289 11
    public static function LEFT($value = '', $chars = 1)
290
    {
291 11
        $value = Functions::flattenSingleValue($value);
292 11
        $chars = Functions::flattenSingleValue($chars);
293
294 11
        if ($chars < 0) {
295 1
            return Functions::VALUE();
296
        }
297
298 10
        if (is_bool($value)) {
299 2
            $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE();
300
        }
301
302 10
        return mb_substr($value, 0, $chars, 'UTF-8');
303
    }
304
305
    /**
306
     * MID.
307
     *
308
     * @param string $value Value
309
     * @param int $start Start character
310
     * @param int $chars Number of characters
311
     *
312
     * @return string
313
     */
314 9
    public static function MID($value = '', $start = 1, $chars = null)
315
    {
316 9
        $value = Functions::flattenSingleValue($value);
317 9
        $start = Functions::flattenSingleValue($start);
318 9
        $chars = Functions::flattenSingleValue($chars);
319
320 9
        if (($start < 1) || ($chars < 0)) {
321 2
            return Functions::VALUE();
322
        }
323
324 7
        if (is_bool($value)) {
325 2
            $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE();
326
        }
327
328 7
        if (empty($chars)) {
329 1
            return '';
330
        }
331
332 6
        return mb_substr($value, --$start, $chars, 'UTF-8');
333
    }
334
335
    /**
336
     * RIGHT.
337
     *
338
     * @param string $value Value
339
     * @param int $chars Number of characters
340
     *
341
     * @return string
342
     */
343 11
    public static function RIGHT($value = '', $chars = 1)
344
    {
345 11
        $value = Functions::flattenSingleValue($value);
346 11
        $chars = Functions::flattenSingleValue($chars);
347
348 11
        if ($chars < 0) {
349 1
            return Functions::VALUE();
350
        }
351
352 10
        if (is_bool($value)) {
353 2
            $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE();
354
        }
355
356 10
        return mb_substr($value, mb_strlen($value, 'UTF-8') - $chars, $chars, 'UTF-8');
357
    }
358
359
    /**
360
     * STRINGLENGTH.
361
     *
362
     * @param string $value Value
363
     *
364
     * @return int
365
     */
366 11
    public static function STRINGLENGTH($value = '')
367
    {
368 11
        $value = Functions::flattenSingleValue($value);
369
370 11
        if (is_bool($value)) {
371 2
            $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE();
372
        }
373
374 11
        return mb_strlen($value, 'UTF-8');
375
    }
376
377
    /**
378
     * LOWERCASE.
379
     *
380
     * Converts a string value to upper case.
381
     *
382
     * @param string $mixedCaseString
383
     *
384
     * @return string
385
     */
386 4
    public static function LOWERCASE($mixedCaseString)
387
    {
388 4
        $mixedCaseString = Functions::flattenSingleValue($mixedCaseString);
389
390 4
        if (is_bool($mixedCaseString)) {
391 2
            $mixedCaseString = ($mixedCaseString) ? Calculation::getTRUE() : Calculation::getFALSE();
392
        }
393
394 4
        return StringHelper::strToLower($mixedCaseString);
395
    }
396
397
    /**
398
     * UPPERCASE.
399
     *
400
     * Converts a string value to upper case.
401
     *
402
     * @param string $mixedCaseString
403
     *
404
     * @return string
405
     */
406 4
    public static function UPPERCASE($mixedCaseString)
407
    {
408 4
        $mixedCaseString = Functions::flattenSingleValue($mixedCaseString);
409
410 4
        if (is_bool($mixedCaseString)) {
411 2
            $mixedCaseString = ($mixedCaseString) ? Calculation::getTRUE() : Calculation::getFALSE();
412
        }
413
414 4
        return StringHelper::strToUpper($mixedCaseString);
415
    }
416
417
    /**
418
     * PROPERCASE.
419
     *
420
     * Converts a string value to upper case.
421
     *
422
     * @param string $mixedCaseString
423
     *
424
     * @return string
425
     */
426 3
    public static function PROPERCASE($mixedCaseString)
427
    {
428 3
        $mixedCaseString = Functions::flattenSingleValue($mixedCaseString);
429
430 3
        if (is_bool($mixedCaseString)) {
431 2
            $mixedCaseString = ($mixedCaseString) ? Calculation::getTRUE() : Calculation::getFALSE();
432
        }
433
434 3
        return StringHelper::strToTitle($mixedCaseString);
435
    }
436
437
    /**
438
     * REPLACE.
439
     *
440
     * @param string $oldText String to modify
441
     * @param int $start Start character
442
     * @param int $chars Number of characters
443
     * @param string $newText String to replace in defined position
444
     *
445
     * @return string
446
     */
447 5
    public static function REPLACE($oldText, $start, $chars, $newText)
448
    {
449 5
        $oldText = Functions::flattenSingleValue($oldText);
450 5
        $start = Functions::flattenSingleValue($start);
451 5
        $chars = Functions::flattenSingleValue($chars);
452 5
        $newText = Functions::flattenSingleValue($newText);
453
454 5
        $left = self::LEFT($oldText, $start - 1);
455 5
        $right = self::RIGHT($oldText, self::STRINGLENGTH($oldText) - ($start + $chars) + 1);
456
457 5
        return $left . $newText . $right;
458
    }
459
460
    /**
461
     * SUBSTITUTE.
462
     *
463
     * @param string $text Value
464
     * @param string $fromText From Value
465
     * @param string $toText To Value
466
     * @param int $instance Instance Number
467
     *
468
     * @return string
469
     */
470 6
    public static function SUBSTITUTE($text = '', $fromText = '', $toText = '', $instance = 0)
471
    {
472 6
        $text = Functions::flattenSingleValue($text);
473 6
        $fromText = Functions::flattenSingleValue($fromText);
474 6
        $toText = Functions::flattenSingleValue($toText);
475 6
        $instance = floor(Functions::flattenSingleValue($instance));
476
477 6
        if ($instance == 0) {
478 4
            return str_replace($fromText, $toText, $text);
479
        }
480
481 2
        $pos = -1;
482 2
        while ($instance > 0) {
483 2
            $pos = mb_strpos($text, $fromText, $pos + 1, 'UTF-8');
484 2
            if ($pos === false) {
485 1
                break;
486
            }
487 1
            --$instance;
488
        }
489
490 2
        if ($pos !== false) {
0 ignored issues
show
introduced by
The condition $pos !== false is always true.
Loading history...
491 1
            return self::REPLACE($text, ++$pos, mb_strlen($fromText, 'UTF-8'), $toText);
492
        }
493
494 1
        return $text;
495
    }
496
497
    /**
498
     * RETURNSTRING.
499
     *
500
     * @param mixed $testValue Value to check
501
     *
502
     * @return null|string
503
     */
504 5
    public static function RETURNSTRING($testValue = '')
505
    {
506 5
        $testValue = Functions::flattenSingleValue($testValue);
507
508 5
        if (is_string($testValue)) {
509 2
            return $testValue;
510
        }
511
512 3
        return null;
513
    }
514
515
    /**
516
     * TEXTFORMAT.
517
     *
518
     * @param mixed $value Value to check
519
     * @param string $format Format mask to use
520
     *
521
     * @return string
522
     */
523 13
    public static function TEXTFORMAT($value, $format)
524
    {
525 13
        $value = Functions::flattenSingleValue($value);
526 13
        $format = Functions::flattenSingleValue($format);
527
528 13
        if ((is_string($value)) && (!is_numeric($value)) && Date::isDateTimeFormatCode($format)) {
529 2
            $value = DateTime::DATEVALUE($value);
530
        }
531
532 13
        return (string) NumberFormat::toFormattedString($value, $format);
533
    }
534
535
    /**
536
     * VALUE.
537
     *
538
     * @param mixed $value Value to check
539
     *
540
     * @return bool
541
     */
542 10
    public static function VALUE($value = '')
543
    {
544 10
        $value = Functions::flattenSingleValue($value);
545
546 10
        if (!is_numeric($value)) {
547 8
            $numberValue = str_replace(
548 8
                StringHelper::getThousandsSeparator(),
549 8
                '',
550 8
                trim($value, " \t\n\r\0\x0B" . StringHelper::getCurrencyCode())
551
            );
552 8
            if (is_numeric($numberValue)) {
553 3
                return (float) $numberValue;
0 ignored issues
show
Bug Best Practice introduced by
The expression return (double)$numberValue returns the type double which is incompatible with the documented return type boolean.
Loading history...
554
            }
555
556 5
            $dateSetting = Functions::getReturnDateType();
557 5
            Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
558
559 5
            if (strpos($value, ':') !== false) {
560 2
                $timeValue = DateTime::TIMEVALUE($value);
561 2
                if ($timeValue !== Functions::VALUE()) {
562 2
                    Functions::setReturnDateType($dateSetting);
563
564 2
                    return $timeValue;
565
                }
566
            }
567 3
            $dateValue = DateTime::DATEVALUE($value);
568 3
            if ($dateValue !== Functions::VALUE()) {
569 1
                Functions::setReturnDateType($dateSetting);
570
571 1
                return $dateValue;
572
            }
573 2
            Functions::setReturnDateType($dateSetting);
574
575 2
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type boolean.
Loading history...
576
        }
577
578 2
        return (float) $value;
0 ignored issues
show
Bug Best Practice introduced by
The expression return (double)$value returns the type double which is incompatible with the documented return type boolean.
Loading history...
579
    }
580
581
    /**
582
     * Compares two text strings and returns TRUE if they are exactly the same, FALSE otherwise.
583
     * EXACT is case-sensitive but ignores formatting differences.
584
     * Use EXACT to test text being entered into a document.
585
     *
586
     * @param $value1
587
     * @param $value2
588
     *
589
     * @return bool
590
     */
591 7
    public static function EXACT($value1, $value2)
592
    {
593 7
        $value1 = Functions::flattenSingleValue($value1);
594 7
        $value2 = Functions::flattenSingleValue($value2);
595
596 7
        return (string) $value2 === (string) $value1;
597
    }
598
}
599