Passed
Push — master ( c4035d...4d6446 )
by Gabriel
07:43
created

Str::fromHex()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 4
c 1
b 0
f 1
dl 0
loc 7
ccs 0
cts 5
cp 0
rs 10
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Nip\Utility;
4
5
/**
6
 * Class Str
7
 * @package Nip\Utility
8
 */
9
class Str
10
{
11
    /**
12
     * The cache of snake-cased words.
13
     *
14
     * @var array
15
     */
16
    protected static $snakeCache = [];
17
18
    /**
19
     * The cache of camel-cased words.
20
     *
21
     * @var array
22
     */
23
    protected static $camelCache = [];
24
25
    /**
26
     * The cache of studly-cased words.
27
     *
28
     * @var array
29
     */
30
    protected static $studlyCache = [];
31
32
    /**
33
     * Return the remainder of a string after the first occurrence of a given value.
34
     *
35
     * @param string $subject
36
     * @param string $search
37
     * @return string
38
     */
39
    public static function after($subject, $search)
40
    {
41
        return $search === '' ? $subject : array_reverse(explode($search, $subject, 2))[0];
42
    }
43
44
    /**
45
     * Return the remainder of a string after the last occurrence of a given value.
46
     *
47
     * @param string $subject
48
     * @param string $search
49
     * @return string
50
     */
51
    public static function afterLast($subject, $search)
52
    {
53
        if ($search === '') {
54
            return $subject;
55
        }
56
57
        $position = strrpos($subject, (string)$search);
58
59
        if ($position === false) {
60
            return $subject;
61
        }
62
63
        return substr($subject, $position + strlen($search));
64
    }
65
66
67
    /**
68
     * Get the portion of a string before the first occurrence of a given value.
69
     *
70
     * @param string $subject
71
     * @param string $search
72
     * @return string
73
     */
74
    public static function before($subject, $search)
75
    {
76
        return $search === '' ? $subject : explode($search, $subject)[0];
77
    }
78
79
    /**
80
     * Get the portion of a string before the last occurrence of a given value.
81
     *
82
     * @param string $subject
83
     * @param string $search
84
     * @return string
85
     */
86
    public static function beforeLast($subject, $search)
87
    {
88
        if ($search === '') {
89
            return $subject;
90
        }
91
92
        $pos = mb_strrpos($subject, $search);
93
94
        if ($pos === false) {
95
            return $subject;
96
        }
97
98
        return static::substr($subject, 0, $pos);
99
    }
100
101
    /**
102
     * Convert a value to camel case.
103
     *
104
     * @param string $value
105
     * @return string
106
     */
107
    public static function camel($value)
108
    {
109
        if (isset(static::$camelCache[$value])) {
110
            return static::$camelCache[$value];
111
        }
112
        return static::$camelCache[$value] = lcfirst(static::studly($value));
113
    }
114
115
    /**
116
     * Convert a value to studly caps case.
117
     *
118
     * @param string $value
119
     * @return string
120
     */
121
    public static function studly($value)
122
    {
123
        $key = $value;
124
        if (isset(static::$studlyCache[$key])) {
125
            return static::$studlyCache[$key];
126
        }
127
        $value = ucwords(str_replace(['-', '_'], ' ', $value));
128
        return static::$studlyCache[$key] = str_replace(' ', '', $value);
129
    }
130
131
    /**
132
     * Determine if a given string ends with a given substring.
133
     *
134
     * @param string $haystack
135
     * @param string|array $needles
136
     * @return bool
137
     */
138
    public static function endsWith($haystack, $needles)
139
    {
140
        foreach ((array)$needles as $needle) {
141
            if (substr($haystack, -strlen($needle)) === (string)$needle) {
142
                return true;
143
            }
144
        }
145
        return false;
146
    }
147
148
    /**
149
     * Cap a string with a single instance of a given value.
150
     *
151
     * @param string $value
152
     * @param string $cap
153
     * @return string
154
     */
155
    public static function finish($value, $cap)
156
    {
157
        $quoted = preg_quote($cap, '/');
158
        return preg_replace('/(?:' . $quoted . ')+$/u', '', $value) . $cap;
159
    }
160
161
    /**
162
     * Determine if a given string matches a given pattern.
163
     *
164
     * @param string $pattern
165
     * @param string $value
166
     * @return bool
167
     */
168
    public static function is($pattern, $value)
169
    {
170
        if ($pattern == $value) {
171
            return true;
172
        }
173
        $pattern = preg_quote($pattern, '#');
174
        // Asterisks are translated into zero-or-more regular expression wildcards
175
        // to make it convenient to check if the strings starts with the given
176
        // pattern such as "library/*", making any string check convenient.
177
        $pattern = str_replace('\*', '.*', $pattern);
178
        return (bool)preg_match('#^' . $pattern . '\z#u', $value);
179
    }
180
181
    /**
182
     * Convert a string to kebab case.
183
     *
184
     * @param string $value
185
     * @return string
186
     */
187
    public static function kebab($value)
188
    {
189
        return static::snake($value, '-');
190
    }
191
192
    /**
193
     * Convert a string to snake case.
194
     *
195
     * @param string $value
196
     * @param string $delimiter
197
     * @return string
198
     */
199
    public static function snake($value, $delimiter = '_')
200
    {
201
        $key = $value;
202
        if (isset(static::$snakeCache[$key][$delimiter])) {
203
            return static::$snakeCache[$key][$delimiter];
204
        }
205
        if (!ctype_lower($value)) {
206
            $value = preg_replace('/\s+/u', '', $value);
207
            $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value));
208
        }
209
        return static::$snakeCache[$key][$delimiter] = $value;
210
    }
211
212
    /**
213
     * Convert the given string to lower-case.
214
     *
215
     * @param string $value
216
     * @return string
217
     */
218
    public static function lower($value)
219
    {
220
        return mb_strtolower($value, 'UTF-8');
221
    }
222
223
    /**
224
     * Limit the number of characters in a string.
225
     *
226
     * @param string $value
227
     * @param int $limit
228
     * @param string $end
229
     * @return string
230
     */
231
    public static function limit($value, $limit = 100, $end = '...')
232
    {
233
        if (mb_strwidth($value, 'UTF-8') <= $limit) {
234
            return $value;
235
        }
236
237
        /** @noinspection PhpComposerExtensionStubsInspection */
238
        return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')) . $end;
239
    }
240
241
    /**
242
     * Limit the number of words in a string.
243
     *
244
     * @param string $value
245
     * @param int $words
246
     * @param string $end
247
     * @return string
248
     */
249
    public static function words($value, $words = 100, $end = '...')
250
    {
251
        preg_match('/^\s*+(?:\S++\s*+){1,' . $words . '}/u', $value, $matches);
252
        if (!isset($matches[0]) || static::length($value) === static::length($matches[0])) {
253
            return $value;
254
        }
255
        return rtrim($matches[0]) . $end;
256
    }
257
258
    /**
259
     * Return the length of the given string.
260
     *
261
     * @param string $value
262
     * @return int
263
     */
264
    public static function length($value)
265
    {
266
        return mb_strlen($value);
267
    }
268
269
    /**
270
     * Parse a Class(at)method style callback into class and method.
271
     *
272
     * @param string $callback
273
     * @param string|null $default
274
     * @return array
275
     */
276
    public static function parseCallback($callback, $default = null)
277
    {
278
        return static::contains($callback, '@') ? explode('@', $callback, 2) : [$callback, $default];
279
    }
280
281
    /**
282
     * Determine if a given string contains a given substring.
283
     *
284
     * @param string $haystack
285
     * @param string|array $needles
286
     * @return bool
287
     */
288
    public static function contains($haystack, $needles)
289
    {
290
        foreach ((array)$needles as $needle) {
291
            if ($needle != '' && mb_strpos($haystack, $needle) !== false) {
292
                return true;
293
            }
294
        }
295
        return false;
296
    }
297
298
    /**
299
     * Get the plural form of an English word.
300
     *
301
     * @param string $value
302
     * @param int $count
303
     * @return string
304
     */
305
    public static function plural($value, $count = 2)
306
    {
307
        return Pluralizer::plural($value, $count);
0 ignored issues
show
Bug introduced by
The type Nip\Utility\Pluralizer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
308
    }
309
310
    /**
311
     * Generate a more truly "random" alpha-numeric string.
312
     *
313
     * @param int $length
314
     * @return string
315
     * @throws \Exception
316
     */
317
    public static function random($length = 16)
318
    {
319
        $string = '';
320
        while (($len = strlen($string)) < $length) {
321
            $size = $length - $len;
322
            $bytes = random_bytes($size);
323
            $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
324
        }
325
        return $string;
326
    }
327
328
    /**
329
     * Replace a given value in the string sequentially with an array.
330
     *
331
     * @param string $search
332
     * @param array $replace
333
     * @param string $subject
334
     * @return string
335
     */
336
    public static function replaceArray($search, array $replace, $subject)
337
    {
338
        foreach ($replace as $value) {
339
            $subject = static::replaceFirst($search, $value, $subject);
340
        }
341
        return $subject;
342
    }
343
344
    /**
345
     * Replace the first occurrence of a given value in the string.
346
     *
347
     * @param string $search
348
     * @param string $replace
349
     * @param string $subject
350
     * @return string
351
     */
352
    public static function replaceFirst($search, $replace, $subject)
353
    {
354
        $position = strpos($subject, $search);
355
        if ($position !== false) {
356
            return substr_replace($subject, $replace, $position, strlen($search));
357
        }
358
        return $subject;
359
    }
360
361
    /**
362
     * Replace the last occurrence of a given value in the string.
363
     *
364
     * @param string $search
365
     * @param string $replace
366
     * @param string $subject
367
     * @return string
368
     */
369
    public static function replaceLast($search, $replace, $subject)
370
    {
371
        $position = strrpos($subject, $search);
372
        if ($position !== false) {
373
            return substr_replace($subject, $replace, $position, strlen($search));
374
        }
375
        return $subject;
376
    }
377
378
    /**
379
     * Convert the given string to title case.
380
     *
381
     * @param string $value
382
     * @return string
383
     */
384
    public static function title($value)
385
    {
386
        return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');
387
    }
388
389
    /**
390
     * Get the singular form of an English word.
391
     *
392
     * @param string $value
393
     * @return string
394
     */
395
    public static function singular($value)
396
    {
397
        return Pluralizer::singular($value);
398
    }
399
400
    /**
401
     * Generate a URL friendly "slug" from a given string.
402
     *
403
     * @param string $title
404
     * @param string $separator
405
     * @return string
406
     */
407
    public static function slug($title, $separator = '-')
408
    {
409
        $title = static::ascii($title);
410
        // Convert all dashes/underscores into separator
411
        $flip = $separator == '-' ? '_' : '-';
412
        $title = preg_replace('![' . preg_quote($flip) . ']+!u', $separator, $title);
413
        // Remove all characters that are not the separator, letters, numbers, or whitespace.
414
        $title = preg_replace('![^' . preg_quote($separator) . '\pL\pN\s]+!u', '', mb_strtolower($title));
415
        // Replace all separator characters and whitespace by a single separator
416
        $title = preg_replace('![' . preg_quote($separator) . '\s]+!u', $separator, $title);
417
        return trim($title, $separator);
418
    }
419
420
    /**
421
     * Transliterate a UTF-8 value to ASCII.
422
     *
423
     * @param string $value
424
     * @return string
425
     */
426
    public static function ascii($value)
427
    {
428
        foreach (static::charsArray() as $key => $val) {
429
            $value = str_replace($val, $key, $value);
430
        }
431
        return preg_replace('/[^\x20-\x7E]/u', '', $value);
432
    }
433
434
    /**
435
     * Returns the replacements for the ascii method.
436
     *
437
     * Note: Adapted from Stringy\Stringy.
438
     *
439
     * @see https://github.com/danielstjules/Stringy/blob/2.3.1/LICENSE.txt
440
     *
441
     * @return array
442
     */
443
    protected static function charsArray()
444
    {
445
        static $charsArray;
446
        if (isset($charsArray)) {
447
            return $charsArray;
448
        }
449
        return $charsArray = require dirname(__DIR__) . '/data/charsArray.php';
450
    }
451
452
    /**
453
     * Determine if a given string starts with a given substring.
454
     *
455
     * @param string $haystack
456
     * @param string|array $needles
457
     * @return bool
458
     */
459
    public static function startsWith($haystack, $needles)
460
    {
461
        foreach ((array)$needles as $needle) {
462
            if ($needle != '' && substr($haystack, 0, strlen($needle)) === (string)$needle) {
463
                return true;
464
            }
465
        }
466
        return false;
467
    }
468
469
    /**
470
     * Make a string's first character uppercase.
471
     *
472
     * @param string $string
473
     * @return string
474
     */
475
    public static function ucfirst($string)
476
    {
477
        return static::upper(static::substr($string, 0, 1)) . static::substr($string, 1);
478
    }
479
480
    /**
481
     * Convert the given string to upper-case.
482
     *
483
     * @param string $value
484
     * @return string
485
     */
486
    public static function upper($value)
487
    {
488
        return mb_strtoupper($value, 'UTF-8');
489
    }
490
491
    /**
492
     * Returns the portion of string specified by the start and length parameters.
493
     *
494
     * @param string $string
495
     * @param int $start
496
     * @param int|null $length
497
     * @return string
498
     */
499
    public static function substr($string, $start, $length = null)
500
    {
501
        return mb_substr($string, $start, $length, 'UTF-8');
502
    }
503
504
    /**
505
     * @param $data
506
     * @param bool $strict
507
     * @return bool
508
     */
509
    public static function isSerialized($data, $strict = true)
510
    {
511
        // if it isn't a string, it isn't serialized.
512
        if (!is_string($data)) {
513
            return false;
514
        }
515
        $data = trim($data);
516
        if ('N;' == $data) {
517
            return true;
518
        }
519
        if (strlen($data) < 4) {
520
            return false;
521
        }
522
        if (':' !== $data[1]) {
523
            return false;
524
        }
525
        if ($strict) {
526
            $lastc = substr($data, -1);
527
            if (';' !== $lastc && '}' !== $lastc) {
528
                return false;
529
            }
530
        } else {
531
            $semicolon = strpos($data, ';');
532
            $brace = strpos($data, '}');
533
            // Either ; or } must exist.
534
            if (false === $semicolon && false === $brace) {
535
                return false;
536
            }
537
            // But neither must be in the first X characters.
538
            if (false !== $semicolon && $semicolon < 3) {
539
                return false;
540
            }
541
            if (false !== $brace && $brace < 4) {
542
                return false;
543
            }
544
        }
545
        $token = $data[0];
546
        switch ($token) {
547
            case 's':
548
                if ($strict) {
549
                    if ('"' !== substr($data, -2, 1)) {
550
                        return false;
551
                    }
552
                } elseif (false === strpos($data, '"')) {
553
                    return false;
554
                }
555
            // or else fall through
556
            // no break
557
            case 'a':
558
            case 'O':
559
                return (bool)preg_match("/^{$token}:[0-9]+:/s", $data);
560
            case 'b':
561
            case 'i':
562
            case 'd':
563
                $end = $strict ? '$' : '';
564
                return (bool)preg_match("/^{$token}:[0-9.E-]+;$end/", $data);
565
        }
566
        return false;
567
    }
568
569
    /**
570
     * @param $str
571
     * @param $first
572
     * @param $last
573
     * @return string
574
     */
575 9
    public static function mask($str, $first = 0, $last = 0)
576
    {
577 9
        $len = strlen($str);
578 9
        $toShow = $first + $last;
579 9
        return substr($str, 0, $len <= $toShow ? 0 : $first)
580 9
            . str_repeat("*", $len - ($len <= $toShow ? 0 : $toShow))
581 9
            . substr($str, $len - $last, $len <= $toShow ? 0 : $last);
582
    }
583
584
    /**
585
     * @param $name
586
     * @param string $separator
587
     * @return string
588
     */
589 3
    public static function initials($name, $separator = '.')
590
    {
591 3
        $name = str_replace(['-', '_'], ' ', $name);
592 3
        $split = explode(" ", $name);
593 3
        $initials = [];
594 3
        foreach ($split as $part) {
595 3
            $initials[] = ucfirst($part[0]);
596
        }
597
598 3
        return implode($separator, $initials) . $separator;
599
    }
600
601
    /**
602
     * @param string $string
603
     * @param bool $return
604
     * @param array $params
605
     * @return bool|mixed
606
     */
607 5
    public static function isJson(string $string, $return = false, ...$params)
608
    {
609 5
        $data = json_decode($string, ...$params);
0 ignored issues
show
Bug introduced by
$params is expanded, but the parameter $assoc of json_decode() does not expect variable arguments. ( Ignorable by Annotation )

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

609
        $data = json_decode($string, /** @scrutinizer ignore-type */ ...$params);
Loading history...
610 5
        if (json_last_error() !== JSON_ERROR_NONE) {
611 1
            return false;
612
        }
613 4
        return $return ? $data : true;
614
    }
615
616
    public function fromHex($hex): string
617
    {
618
        $str = '';
619
        for ($i=0;$i<strlen($hex);$i+=2) {
620
            $str .= chr(hexdec(substr($hex, $i, 2)));
0 ignored issues
show
Bug introduced by
It seems like hexdec(substr($hex, $i, 2)) can also be of type double; however, parameter $ascii of chr() 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

620
            $str .= chr(/** @scrutinizer ignore-type */ hexdec(substr($hex, $i, 2)));
Loading history...
621
        }
622
        return $str;
623
    }
624
}
625