Completed
Push — master ( 84d590...3b0909 )
by Lorenzo
01:44
created

string.php ➔ charsArrayRegEx()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 51
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 42
nc 1
nop 0
dl 0
loc 51
rs 9.4109
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Generate random string (password) from a different charset based on $secLevel.
5
 * $secLevel=0 [a-z] charset.
6
 * $secLevel=1 [a-z0-9] charset.
7
 * $secLevel=2 [A-Za-z0-9] charset.
8
 * $secLevel=3 [A-Za-z0-9-_$!+&%?=*#@] charset.
9
 * @param int $length
10
 * @param int $secLevel
11
 * @return string
12
 */
13
function generateRandomPassword(int $length = 10, int $secLevel = 2) : string
14
{
15
    $charset = 'abcdefghijklmnopqrstuvwxyz';
16
    if ($secLevel == 1) {
17
        $charset = 'abcdefghijklmnopqrstuvwxyz1234567890';
18
    } elseif ($secLevel == 2) {
19
        $charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
20
    } elseif ($secLevel >= 3) {
21
        $charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-_$!+&%?=*#@';
22
    }
23
24
    return generateRandomString($length, '', $charset);
25
}
26
27
/**
28
 * Generate random string from [0-9A-Za-z] charset.
29
 * You may extend charset by passing $extChars (i.e. add these chars to existing).
30
 * Ex.: $extChars='-_$!' implies that the final charset is [0-9A-Za-z-_$!]
31
 * If $newChars is set, the default charset are replaced by this and $extChars was ignored.
32
 * Ex.: $newChars='0123456789' implies that the final charset is [0123456789]
33
 * @param int $length
34
 * @param string $extChars
35
 * @param string $newChars
36
 * @return string
37
 */
38
function generateRandomString(int $length = 10, string $extChars = '', string $newChars = '') : string
39
{
40
    if ($length < 1) {
41
        $length = 1;
42
    }
43
44
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
45
    if ($newChars !== null && $newChars != '') {
46
        $characters = $newChars;
47
    } elseif ($extChars !== null && $extChars != '') {
48
        $characters .= $extChars;
49
    }
50
51
    $charactersLength = strlen($characters);
52
    $randomString = '';
53
54
    for ($i = 0; $i < $length; $i++) {
55
        $randomString .= $characters[random_int(0, $charactersLength - 1)];
56
    }
57
58
    return $randomString;
59
}
60
61
/**
62
 * *****************************************************
63
 * LARAVEL STRING HELPERS
64
 * With some adjustments
65
 * *****************************************************
66
 */
67
68
if (!function_exists('preg_replace_sub')) {
69
    /**
70
     * Replace a given pattern with each value in the array in sequentially.
71
     *
72
     * @param  string $pattern
73
     * @param  array $replacements
74
     * @param  string $subject
75
     * @return string
76
     */
77
    function preg_replace_sub($pattern, &$replacements, $subject)
78
    {
79
        return preg_replace_callback($pattern, function () use (&$replacements) {
80
            return array_shift($replacements);
81
        }, $subject);
82
    }
83
}
84
85
if (!function_exists('snake_case')) {
86
    /**
87
     * Convert a string to snake case.
88
     *
89
     * @param  string $value
90
     * @param  string $delimiter
91
     * @return string
92
     */
93
    function snake_case($value, $delimiter = '_')
94
    {
95
        $snakeCache = [];
96
        $key = $value . $delimiter;
97
        if (isset($snakeCache[$key])) {
98
            return $snakeCache[$key];
99
        }
100
        if (!ctype_lower($value)) {
101
            $value = strtolower(preg_replace('/(.)(?=[A-Z])/', '$1' . $delimiter, $value));
102
        }
103
        return $snakeCache[$key] = $value;
104
    }
105
}
106
107
if (!function_exists('str_random')) {
108
    /**
109
     * Generate a more truly "random" alpha-numeric string with openssl.
110
     * If openssl_random_pseudo_bytes not exists, use simple legacy function
111
     *
112
     * @param  int $length
113
     * @return string
114
     *
115
     * @throws \RuntimeException
116
     */
117
    function str_random(int $length = 16)
118
    {
119
        if ($length < 0) {
120
            $length = 16;
121
        }
122
123
        if (!function_exists('openssl_random_pseudo_bytes')) {
124
            return generateRandomString($length);
125
        }
126
        $bytes = openssl_random_pseudo_bytes($length * 2);
127
        if ($bytes === false) {
128
            throw new RuntimeException('Unable to generate random string.');
129
        }
130
        return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $length);
131
    }
132
}
133
134
if (!function_exists('ends_with')) {
135
    /**
136
     * Determine if a given string ends with a given substring.
137
     *
138
     * @param  string $haystack
139
     * @param  string|array $needles
140
     * @return bool
141
     */
142
    function ends_with($haystack, $needles)
143
    {
144
        if (isNullOrEmpty($haystack) || isNullOrEmpty($needles)) {
145
            return false;
146
        }
147
148
        foreach ((array)$needles as $needle) {
149
            if ((string)$needle === substr($haystack, -strlen($needle))) {
150
                return true;
151
            }
152
        }
153
        return false;
154
    }
155
}
156
157 View Code Duplication
if (!function_exists('ends_with_insensitive')) {
158
    /**
159
     * Determine if a given string ends with a given substring (case insensitive).
160
     *
161
     * @param  string $haystack
162
     * @param  string|array $needles
163
     * @return bool
164
     */
165
    function ends_with_insensitive($haystack, $needles)
166
    {
167
        if (isNullOrEmpty($haystack) || isNullOrEmpty($needles)) {
168
            return false;
169
        }
170
171
        $haystack = strtolower($haystack);
172
        $needles = strtolower($needles);
173
174
        return ends_with($haystack, $needles);
175
    }
176
}
177
178
if (!function_exists('starts_with')) {
179
    /**
180
     * Determine if a given string starts with a given substring.
181
     *
182
     * @param  string $haystack
183
     * @param  string|array $needles
184
     * @return bool
185
     */
186
    function starts_with($haystack, $needles)
187
    {
188
        if (isNullOrEmpty($haystack) || (!is_array($needles) && isNullOrEmpty($needles))) {
189
            return false;
190
        }
191
192
        foreach ((array)$needles as $needle) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
193
            if ($needle != '' && strpos($haystack, $needle) === 0) {
194
                return true;
195
            }
196
        }
197
        return false;
198
    }
199
}
200
201 View Code Duplication
if (!function_exists('starts_with_insensitive')) {
202
    /**
203
     * Determine if a given string starts with a given substring (case insensitive).
204
     *
205
     * @param  string $haystack
206
     * @param  string|array $needles
207
     * @return bool
208
     */
209
    function starts_with_insensitive($haystack, $needles)
210
    {
211
        if (isNullOrEmpty($haystack) || (!is_array($needles) && isNullOrEmpty($needles))) {
212
            return false;
213
        }
214
215
        $haystack = strtolower($haystack);
216
        $needles = strtolower($needles);
217
218
        return starts_with($haystack, $needles);
219
    }
220
}
221
222
if (!function_exists('str_contains')) {
223
    /**
224
     * Determine if a given string contains a given substring.
225
     *
226
     * @param  string $haystack
227
     * @param  string|array $needles
228
     * @return bool
229
     */
230
    function str_contains(string $haystack, $needles)
231
    {
232
        if (isNullOrEmpty($haystack)) {
233
            return false;
234
        }
235
        if ((is_array($needles) && isNullOrEmptyArray($needles))
236
            || (!is_array($needles) && isNullOrEmpty($needles))
237
        ) {
238
            return false;
239
        }
240
241
        foreach ((array)$needles as $needle) {
242
            if ($needle != '' && strpos($haystack, $needle) !== false) {
243
                return true;
244
            }
245
        }
246
        return false;
247
    }
248
}
249
250 View Code Duplication
if (!function_exists('str_contains_insensitive')) {
251
    /**
252
     * Determine if a given string contains a given substring (case insensitive).
253
     *
254
     * @param  string $haystack
255
     * @param  string|array $needles
256
     * @return bool
257
     */
258
    function str_contains_insensitive($haystack, $needles)
259
    {
260
        if (isNullOrEmpty($haystack) || isNullOrEmpty($needles)) {
261
            return false;
262
        }
263
264
        $haystack = strtolower($haystack);
265
        $needles = strtolower($needles);
266
267
        return str_contains($haystack, $needles);
268
    }
269
}
270
271
if (!function_exists('str_finish')) {
272
    /**
273
     * Cap a string with a single instance of a given value.
274
     *
275
     * @param  string $value
276
     * @param  string $cap
277
     * @return string
278
     */
279
    function str_finish($value, $cap)
280
    {
281
        if (isNullOrEmpty($value) || isNullOrEmpty($cap)) {
282
            return false;
283
        }
284
285
        $quoted = preg_quote($cap, '/');
286
        return preg_replace('/(?:' . $quoted . ')+$/', '', $value) . $cap;
287
    }
288
}
289
290 View Code Duplication
if (!function_exists('str_finish_insensitive')) {
291
    /**
292
     * Cap a string with a single instance of a given value (Case Insensitive).
293
     *
294
     * @param  string $value
295
     * @param  string $cap
296
     * @return string
297
     */
298
    function str_finish_insensitive($value, $cap)
299
    {
300
        if (isNullOrEmpty($value) || isNullOrEmpty($cap)) {
301
            return false;
302
        }
303
304
        $value = strtolower($value);
305
        $cap = strtolower($cap);
306
307
        return str_finish($value, $cap);
308
    }
309
}
310
311
if (!function_exists('str_is')) {
312
    /**
313
     * Determine if a given string matches a given pattern.
314
     *
315
     * @param  string $pattern
316
     * @param  string $value
317
     * @return bool
318
     */
319
    function str_is($pattern, $value)
320
    {
321
        if ($pattern == $value) {
322
            return true;
323
        }
324
        $pattern = preg_quote($pattern, '#');
325
        // Asterisks are translated into zero-or-more regular expression wildcards
326
        // to make it convenient to check if the strings starts with the given
327
        // pattern such as "library/*", making any string check convenient.
328
        $pattern = str_replace('\*', '.*', $pattern) . '\z';
329
        return preg_match('#^' . $pattern . '#', $value) === 1;
330
    }
331
}
332
if (!function_exists('str_limit')) {
333
    /**
334
     * Limit the number of characters in a string.
335
     *
336
     * @param  string $value
337
     * @param  int $limit
338
     * @param  string $end append in
339
     * @param  bool $wordsafe if set to true, remove any truncated word in the end of string so the result no breaking words.
340
     * @return string
341
     */
342
    function str_limit(string $value, int $limit = 100, string $end = '...', bool $wordsafe = false) : string
343
    {
344
        $limit = max($limit, 0);
345
        if (mb_strlen($value) <= $limit) {
346
            return $value;
347
        }
348
349
        $string = rtrim(mb_substr($value, 0, $limit, 'UTF-8'));
350
        if ($wordsafe) {
351
            $string = preg_replace('/\s+?(\S+)?$/', '', $string);
352
        }
353
        return $string . $end;
354
    }
355
}
356
357
if (!function_exists('str_replace_array')) {
358
    /**
359
     * Replace a given value in the string sequentially with an array.
360
     *
361
     * @param  string $search
362
     * @param  array $replace
363
     * @param  string $subject
364
     * @return string
365
     */
366
    function str_replace_array($search, array $replace, $subject)
367
    {
368
        foreach ($replace as $value) {
369
            $subject = preg_replace('/' . $search . '/', $value, $subject, 1);
370
        }
371
        return $subject;
372
    }
373
}
374
375
if (!function_exists('studly_case')) {
376
    /**
377
     * Convert a value to studly caps case.
378
     *
379
     * @param  string $value
380
     * @return string
381
     */
382
    function studly_case($value)
383
    {
384
        $studlyCache = [];
385
        $key = $value;
386
        if (isset($studlyCache[$key])) {
387
            return $studlyCache[$key];
388
        }
389
        $value = ucwords(str_replace(array('-', '_'), ' ', $value));
390
        return $studlyCache[$key] = str_replace(' ', '', $value);
391
    }
392
}
393
394
if (!function_exists('studly')) {
395
    /**
396
     * Convert a value to studly caps case.
397
     * Alias of studly_case
398
     *
399
     * @param  string $value
400
     * @return string
401
     */
402
    function studly($value)
403
    {
404
        return studly_case($value);
405
    }
406
}
407
408
if (!function_exists('camel_case')) {
409
    /**
410
     * Convert a value to camel case.
411
     *
412
     * @param  string $value
413
     * @return string
414
     */
415
    function camel_case($value)
416
    {
417
        $camelCache = [];
418
        if (isset($camelCache[$value])) {
419
            return $camelCache[$value];
420
        }
421
        return $camelCache[$value] = lcfirst(studly($value));
422
    }
423
}
424
425
/**
426
 * Replace underscores with dashes in the string.
427
 * @param string $word
428
 * @return string
429
 */
430
function underscore2dash(string $word) : string
431
{
432
    return str_replace('_', '-', $word);
433
}
434
435
/**
436
 * Make an underscored, lowercase form from the expression in the string.
437
 * @param string $word
438
 * @return string
439
 */
440
function dash2underscore(string $word) : string
441
{
442
    $word = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2', $word);
443
    $word = preg_replace('/([a-z])([A-Z])/', '\1_\2', $word);
444
    return str_replace('-', '_', strtolower($word));
445
}
446
447
if (!function_exists('str_replace_multiple_space')) {
448
449
    /**
450
     * Replace multiple spaces with one space.
451
     * If $withNbsp replaces "&nbsp;" with a single space before converts multiple sequential spaces.
452
     * @param string $str
453
     * @param bool $withNbsp
454
     * @return string
455
     */
456
    function str_replace_multiple_space(string $str, bool $withNbsp = false) : string
457
    {
458
        if ($withNbsp) {
459
            $str = str_replace('&nbsp;', ' ', $str);
460
        }
461
        return preg_replace('/\s+/', ' ', $str);
462
    }
463
}
464
465
if (!function_exists('str_replace_last')) {
466
    /**
467
     * Replace last occurrence ($search) of a string ($subject) with $replace string.
468
     * @param string $search
469
     * @param string $replace
470
     * @param string $subject
471
     * @return string
472
     */
473
    function str_replace_last(string $search, string $replace, string $subject) : string
474
    {
475
        if ($search == '') {
476
            return $subject;
477
        }
478
        $position = strrpos($subject, $search);
479
        if ($position === false) {
480
            return $subject;
481
        }
482
        return substr_replace($subject, $replace, $position, strlen($search));
483
    }
484
}
485
if (!function_exists('segment')) {
486
487
    /**
488
     * Get a segment from a string based on a delimiter.
489
     * Returns an empty string when the offset doesn't exist.
490
     * Use a negative index to start counting from the last element.
491
     *
492
     * @param string $delimiter
493
     * @param int $index
494
     * @param string $subject
495
     *
496
     * @return string
497
     * @see https://github.com/spatie/string/blob/master/src/Str.php
498
     */
499
    function segment($delimiter, $index, $subject)
500
    {
501
        $segments = explode($delimiter, $subject);
502
        if ($index < 0) {
503
            $segments = array_reverse($segments);
504
            $index = (int)abs($index) - 1;
505
        }
506
        $segment = isset($segments[$index]) ? $segments[$index] : '';
507
        return $segment;
508
    }
509
}
510
if (!function_exists('firstSegment')) {
511
512
    /**
513
     * Get the first segment from a string based on a delimiter.
514
     *
515
     * @param string $delimiter
516
     * @param string $subject
517
     *
518
     * @return string
519
     * @see https://github.com/spatie/string/blob/master/src/Str.php
520
     */
521
    function firstSegment($delimiter, $subject) : string
522
    {
523
        return segment($delimiter, 0, $subject);
524
    }
525
}
526
527
if (!function_exists('lastSegment')) {
528
529
    /**
530
     * Get the last segment from a string based on a delimiter.
531
     *
532
     * @param string $delimiter
533
     * @param string $subject
534
     *
535
     * @return string
536
     * @see https://github.com/spatie/string/blob/master/src/Str.php
537
     */
538
    function lastSegment($delimiter, $subject) : string
539
    {
540
        return segment($delimiter, -1, $subject);
541
    }
542
}
543
/**
544
 * Return true if $subject is null or empty string ('').
545
 * @param $subject
546
 * @param bool $withTrim if set to true (default) check if trim()!='' too.
547
 * @return bool
548
 */
549
function isNullOrEmpty($subject, bool $withTrim = true) : bool
550
{
551
    return $subject === null || $subject == '' || ($withTrim === true && trim($subject) == '');
552
}
553
554
/**
555
 * Return true if $subject is not null and is not empty string ('').
556
 * @param $subject
557
 * @param bool $withTrim if set to true (default) check if trim()!='' too.
558
 * @return bool
559
 */
560
function isNotNullOrEmpty($subject, bool $withTrim = true) : bool
561
{
562
    return !isNullOrEmpty($subject, $withTrim);
563
}
564
565
566
/**
567
 * Convert number to word representation.
568
 *
569
 * @param int $number number to convert to word
570
 * @param string $locale default 'IT' support only IT or EN
571
 *
572
 * @return string converted string
573
 * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
574
 */
575
function numberToWord(int $number, string $locale = 'IT') : string
576
{
577
    if (isNullOrEmpty($locale) || (strtoupper($locale) != 'IT' && strtoupper($locale) != 'EN')) {
578
        $locale = 'IT';
579
    } else {
580
        $locale = strtoupper($locale);
581
    }
582
583
    $hyphen = $locale == 'EN' ? '-' : '';
584
    $conjunction = $locale == 'EN' ? ' and ' : ' ';
585
    $separator = ', ';
586
    $negative = $locale == 'EN' ? 'negative ' : 'negativo ';
587
    $decimal = $locale == 'EN' ? ' point ' : ' punto ';
588
    $fraction = null;
589
    $dictionary = $locale == 'EN' ? NUMBERS_EN_ARR : NUMBERS_ITA_ARR;
590
    if (!is_numeric($number)) {
591
        return '';
592
    }
593
    if (!isInteger($number, false, true)) {
594
        trigger_error('numberToWord only accepts numbers between -' . PHP_INT_MAX . ' and ' . PHP_INT_MAX,
595
            E_USER_WARNING);
596
        return '';
597
    }
598
    if ($number < 0) {
599
        return $negative . numberToWord(abs($number), $locale);
600
    }
601
    if (strpos($number, '.') !== false) {
602
        list($number, $fraction) = explode('.', $number);
603
    }
604
    switch (true) {
605
        case $number < 21:
606
            $string = $dictionary[$number];
607
            break;
608
        case $number < 100:
609
            $tens = ((int)($number / 10)) * 10;
610
            $units = $number % 10;
611
            $string = $dictionary[$tens];
612
            if ($units) {
613
                $string .= $hyphen . $dictionary[$units];
614
            }
615
            break;
616
        case $number < 1000:
617
            $hundreds = $number / 100;
618
            $remainder = $number % 100;
619
            $string = $dictionary[$hundreds] . ' ' . $dictionary[100];
620
            if ($remainder) {
621
                $string .= $conjunction . numberToWord($remainder, $locale);
622
            }
623
            break;
624
        default:
625
            $baseUnit = pow(1000, floor(log($number, 1000)));
626
            $numBaseUnits = (int)($number / $baseUnit);
627
            $remainder = $number % $baseUnit;
628
            $string = numberToWord($numBaseUnits, $locale) . ' ' . $dictionary[$baseUnit];
629
            if ($remainder) {
630
                $string .= $remainder < 100 ? $conjunction : $separator;
631
                $string .= numberToWord($remainder, $locale);
632
            }
633
            break;
634
    }
635
    if (null !== $fraction && is_numeric($fraction)) {
636
        $string .= $decimal;
637
        $words = [];
638
        foreach (str_split((string)$fraction) as $number) {
639
            $words[] = $dictionary[$number];
640
        }
641
        $string .= implode(' ', $words);
642
    }
643
    return $string;
644
}
645
646
/**
647
 * Convert seconds to real time.
648
 *
649
 * @param int $seconds time in seconds
650
 * @param bool $returnAsWords return time in words (example one minute and 20 seconds) if value is True or (1 minute and 20 seconds) if value is false, default false
651
 * @param string $locale 'IT' default, or 'EN'
652
 *
653
 * @return string
654
 * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
655
 */
656
function secondsToText(int $seconds, bool $returnAsWords = false, string $locale = 'IT') : string
657
{
658
    $parts = [];
659
    $arrPeriod = ($locale == 'EN' ? PERIOD_IN_SECONDS_EN_ARR : PERIOD_IN_SECONDS_ITA_ARR);
660
    foreach ($arrPeriod as $name => $dur) {
661
        $div = floor($seconds / $dur);
662
        if ($div == 0) {
663
            continue;
664
        }
665
        if ($div == 1) {
666
            $parts[] = ($returnAsWords ? numberToWord($div, $locale) : $div) . ' ' . $name;
667
        } else {
668
            $parts[] = ($returnAsWords ? numberToWord($div,
669
                    $locale) : $div) . ' ' . ($locale == 'EN' ? $name : PERIOD_SINGULAR_PLURAL_ITA_ARR[$name]) . (strtoupper($locale) == 'EN' ? 's' : '');
670
        }
671
        $seconds %= $dur;
672
    }
673
    $last = array_pop($parts);
674
    if (isNullOrEmptyArray($parts)) {
675
        return $last;
676
    }
677
    return implode(', ', $parts) . (strtoupper($locale) == 'EN' ? ' and ' : ' e ') . $last;
678
}
679
680
681
/**
682
 * Convert minutes to real time.
683
 *
684
 * @param float $minutes time in minutes
685
 * @param bool $returnAsWords return time in words (example one hour and 20 minutes) if value is True or (1 hour and 20 minutes) if value is false, default false
686
 * @param string $locale 'IT' (default) or 'EN'
687
 *
688
 * @return string
689
 * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
690
 */
691
function minutesToText(float $minutes, bool $returnAsWords = false, string $locale = 'IT') : string
692
{
693
    $seconds = $minutes * 60;
694
    return secondsToText($seconds, $returnAsWords, $locale);
695
}
696
697
/**
698
 * Convert hours to real time.
699
 *
700
 * @param float $hours time in hours
701
 * @param bool $returnAsWords return time in words (example one hour) if value is True or (1 hour) if value is false, default false
702
 * @param string $locale 'IT' (default) or 'EN'
703
 *
704
 * @return string
705
 * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
706
 */
707
function hoursToText(float $hours, bool $returnAsWords = false, string $locale = 'IT') : string
708
{
709
    $seconds = $hours * 3600;
710
    return secondsToText($seconds, $returnAsWords, $locale);
711
}
712
713
if (!function_exists('str_html_compress')) {
714
715
    /**
716
     * Removes whitespace from html and compact it.
717
     * @param string $value
718
     * @return string
719
     */
720
    function str_html_compress(string $value) : string
721
    {
722
        return preg_replace(array('/\>[^\S ]+/s', '/[^\S ]+\</s', '/(\s)+/s'), array('>', '<', '\\1'), $value);
723
    }
724
}
725
726
if (!function_exists('str_word_count_utf8')) {
727
728
    /**
729
     * Count number of words in string.
730
     * Return zero if an error occourred.
731
     * @param string $str
732
     * @return int
733
     * @see https://github.com/ifsnop/lpsf/blob/master/src/Ifsnop/functions.inc.php
734
     */
735
    function str_word_count_utf8(string $str) : int
736
    {
737
        $result = preg_match_all("/\p{L}[\p{L}\p{Mn}\p{Pd}'\x{2019}]*/u", $str, $matches);
738
        return $result === false ? 0 : $result;
739
    }
740
}
741
742
if (!function_exists('slugify')) {
743
744
    /**
745
     * Generate a URL friendly "slug" from a given string.
746
     * Converts the string into an URL slug. This includes replacing non-ASCII
747
     * characters with their closest ASCII equivalents, removing remaining
748
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
749
     * $replacement. The replacement defaults to a single dash, and the string
750
     * is also converted to lowercase.
751
     * @param string $title
752
     * @param string $separator
753
     * @return string
754
     * @see normalizeUtf8String in https://github.com/padosoft/support/blob/master/src/sanitize.php#L150
755
     * @see https://github.com/illuminate/support/blob/master/Str.php
756
     */
757
    function slugify(string $title, string $separator = '-') : string
758
    {
759
        //removes all diacritics (marks like accents) from a given UTF8-encoded
760
        //texts and returns ASCii-text equivalent(if possible).
761
        $title = normalizeUtf8String($title);
762
763
        // Convert all dashes/underscores into separator
764
        $flip = $separator == '-' ? '_' : '-';
765
        $title = preg_replace('![' . preg_quote($flip) . ']+!u', $separator, $title);
766
767
        // Remove all characters that are not the separator, letters, numbers, or whitespace.
768
        $title = preg_replace('![^' . preg_quote($separator) . '\pL\pN\s]+!u', '', mb_strtolower($title));
769
770
        // Replace all separator characters and whitespace by a single separator
771
        $title = preg_replace('![' . preg_quote($separator) . '\s]+!u', $separator, $title);
772
773
        return trim($title, $separator);
774
    }
775
}
776
777
if (!function_exists('charsArray')) {
778
    /**
779
     * Returns the replacements for the non-Ascii chars.
780
     *
781
     * @return array An array of replacements.
782
     * @see https://github.com/danielstjules/Stringy/blob/master/src/Stringy.php
783
     */
784
    function charsArray()
785
    {
786
        return array(
787
            '0' => array('°', '₀', '۰'),
788
            '1' => array('¹', '₁', '۱'),
789
            '2' => array('²', '₂', '۲'),
790
            '3' => array('³', '₃', '۳'),
791
            '4' => array('⁴', '₄', '۴', '٤'),
792
            '5' => array('⁵', '₅', '۵', '٥'),
793
            '6' => array('⁶', '₆', '۶', '٦'),
794
            '7' => array('⁷', '₇', '۷'),
795
            '8' => array('⁸', '₈', '۸'),
796
            '9' => array('⁹', '₉', '۹'),
797
            'a' => array(
798
                'à',
799
                'á',
800
                'ả',
801
                'ã',
802
                'ạ',
803
                'ă',
804
                'ắ',
805
                'ằ',
806
                'ẳ',
807
                'ẵ',
808
                'ặ',
809
                'â',
810
                'ấ',
811
                'ầ',
812
                'ẩ',
813
                'ẫ',
814
                'ậ',
815
                'ā',
816
                'ą',
817
                'å',
818
                'α',
819
                'ά',
820
                'ἀ',
821
                'ἁ',
822
                'ἂ',
823
                'ἃ',
824
                'ἄ',
825
                'ἅ',
826
                'ἆ',
827
                'ἇ',
828
                'ᾀ',
829
                'ᾁ',
830
                'ᾂ',
831
                'ᾃ',
832
                'ᾄ',
833
                'ᾅ',
834
                'ᾆ',
835
                'ᾇ',
836
                'ὰ',
837
                'ά',
838
                'ᾰ',
839
                'ᾱ',
840
                'ᾲ',
841
                'ᾳ',
842
                'ᾴ',
843
                'ᾶ',
844
                'ᾷ',
845
                'а',
846
                'أ',
847
                'အ',
848
                'ာ',
849
                'ါ',
850
                'ǻ',
851
                'ǎ',
852
                'ª',
853
                'ა',
854
                'अ',
855
                'ا'
856
            ),
857
            'b' => array('б', 'β', 'Ъ', 'Ь', 'ب', 'ဗ', 'ბ'),
858
            'c' => array('ç', 'ć', 'č', 'ĉ', 'ċ'),
859
            'd' => array(
860
                'ď',
861
                'ð',
862
                'đ',
863
                'ƌ',
864
                'ȡ',
865
                'ɖ',
866
                'ɗ',
867
                'ᵭ',
868
                'ᶁ',
869
                'ᶑ',
870
                'д',
871
                'δ',
872
                'د',
873
                'ض',
874
                'ဍ',
875
                'ဒ',
876
                'დ'
877
            ),
878
            'e' => array(
879
                'é',
880
                'è',
881
                'ẻ',
882
                'ẽ',
883
                'ẹ',
884
                'ê',
885
                'ế',
886
                'ề',
887
                'ể',
888
                'ễ',
889
                'ệ',
890
                'ë',
891
                'ē',
892
                'ę',
893
                'ě',
894
                'ĕ',
895
                'ė',
896
                'ε',
897
                'έ',
898
                'ἐ',
899
                'ἑ',
900
                'ἒ',
901
                'ἓ',
902
                'ἔ',
903
                'ἕ',
904
                'ὲ',
905
                'έ',
906
                'е',
907
                'ё',
908
                'э',
909
                'є',
910
                'ə',
911
                'ဧ',
912
                'ေ',
913
                'ဲ',
914
                'ე',
915
                'ए',
916
                'إ',
917
                'ئ'
918
            ),
919
            'f' => array('ф', 'φ', 'ف', 'ƒ', 'ფ'),
920
            'g' => array('ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ဂ', 'გ', 'گ'),
921
            'h' => array('ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ'),
922
            'i' => array(
923
                'í',
924
                'ì',
925
                'ỉ',
926
                'ĩ',
927
                'ị',
928
                'î',
929
                'ï',
930
                'ī',
931
                'ĭ',
932
                'į',
933
                'ı',
934
                'ι',
935
                'ί',
936
                'ϊ',
937
                'ΐ',
938
                'ἰ',
939
                'ἱ',
940
                'ἲ',
941
                'ἳ',
942
                'ἴ',
943
                'ἵ',
944
                'ἶ',
945
                'ἷ',
946
                'ὶ',
947
                'ί',
948
                'ῐ',
949
                'ῑ',
950
                'ῒ',
951
                'ΐ',
952
                'ῖ',
953
                'ῗ',
954
                'і',
955
                'ї',
956
                'и',
957
                'ဣ',
958
                'ိ',
959
                'ီ',
960
                'ည်',
961
                'ǐ',
962
                'ი',
963
                'इ',
964
                'ی'
965
            ),
966
            'j' => array('ĵ', 'ј', 'Ј', 'ჯ', 'ج'),
967
            'k' => array(
968
                'ķ',
969
                'ĸ',
970
                'к',
971
                'κ',
972
                'Ķ',
973
                'ق',
974
                'ك',
975
                'က',
976
                'კ',
977
                'ქ',
978
                'ک'
979
            ),
980
            'l' => array('ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ'),
981
            'm' => array('м', 'μ', 'م', 'မ', 'მ'),
982
            'n' => array(
983
                'ñ',
984
                'ń',
985
                'ň',
986
                'ņ',
987
                'ʼn',
988
                'ŋ',
989
                'ν',
990
                'н',
991
                'ن',
992
                'န',
993
                'ნ'
994
            ),
995
            'o' => array(
996
                'ó',
997
                'ò',
998
                'ỏ',
999
                'õ',
1000
                'ọ',
1001
                'ô',
1002
                'ố',
1003
                'ồ',
1004
                'ổ',
1005
                'ỗ',
1006
                'ộ',
1007
                'ơ',
1008
                'ớ',
1009
                'ờ',
1010
                'ở',
1011
                'ỡ',
1012
                'ợ',
1013
                'ø',
1014
                'ō',
1015
                'ő',
1016
                'ŏ',
1017
                'ο',
1018
                'ὀ',
1019
                'ὁ',
1020
                'ὂ',
1021
                'ὃ',
1022
                'ὄ',
1023
                'ὅ',
1024
                'ὸ',
1025
                'ό',
1026
                'о',
1027
                'و',
1028
                'θ',
1029
                'ို',
1030
                'ǒ',
1031
                'ǿ',
1032
                'º',
1033
                'ო',
1034
                'ओ'
1035
            ),
1036
            'p' => array('п', 'π', 'ပ', 'პ', 'پ'),
1037
            'q' => array('ყ'),
1038
            'r' => array('ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ'),
1039
            's' => array(
1040
                'ś',
1041
                'š',
1042
                'ş',
1043
                'с',
1044
                'σ',
1045
                'ș',
1046
                'ς',
1047
                'س',
1048
                'ص',
1049
                'စ',
1050
                'ſ',
1051
                'ს'
1052
            ),
1053
            't' => array(
1054
                'ť',
1055
                'ţ',
1056
                'т',
1057
                'τ',
1058
                'ț',
1059
                'ت',
1060
                'ط',
1061
                'ဋ',
1062
                'တ',
1063
                'ŧ',
1064
                'თ',
1065
                'ტ'
1066
            ),
1067
            'u' => array(
1068
                'ú',
1069
                'ù',
1070
                'ủ',
1071
                'ũ',
1072
                'ụ',
1073
                'ư',
1074
                'ứ',
1075
                'ừ',
1076
                'ử',
1077
                'ữ',
1078
                'ự',
1079
                'û',
1080
                'ū',
1081
                'ů',
1082
                'ű',
1083
                'ŭ',
1084
                'ų',
1085
                'µ',
1086
                'у',
1087
                'ဉ',
1088
                'ု',
1089
                'ူ',
1090
                'ǔ',
1091
                'ǖ',
1092
                'ǘ',
1093
                'ǚ',
1094
                'ǜ',
1095
                'უ',
1096
                'उ'
1097
            ),
1098
            'v' => array('в', 'ვ', 'ϐ'),
1099
            'w' => array('ŵ', 'ω', 'ώ', 'ဝ', 'ွ'),
1100
            'x' => array('χ', 'ξ'),
1101
            'y' => array(
1102
                'ý',
1103
                'ỳ',
1104
                'ỷ',
1105
                'ỹ',
1106
                'ỵ',
1107
                'ÿ',
1108
                'ŷ',
1109
                'й',
1110
                'ы',
1111
                'υ',
1112
                'ϋ',
1113
                'ύ',
1114
                'ΰ',
1115
                'ي',
1116
                'ယ'
1117
            ),
1118
            'z' => array('ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ'),
1119
            'aa' => array('ع', 'आ', 'آ'),
1120
            'ae' => array('ä', 'æ', 'ǽ'),
1121
            'ai' => array('ऐ'),
1122
            'at' => array('@'),
1123
            'ch' => array('ч', 'ჩ', 'ჭ', 'چ'),
1124
            'dj' => array('ђ', 'đ'),
1125
            'dz' => array('џ', 'ძ'),
1126
            'ei' => array('ऍ'),
1127
            'gh' => array('غ', 'ღ'),
1128
            'ii' => array('ई'),
1129
            'ij' => array('ij'),
1130
            'kh' => array('х', 'خ', 'ხ'),
1131
            'lj' => array('љ'),
1132
            'nj' => array('њ'),
1133
            'oe' => array('ö', 'œ', 'ؤ'),
1134
            'oi' => array('ऑ'),
1135
            'oii' => array('ऒ'),
1136
            'ps' => array('ψ'),
1137
            'sh' => array('ш', 'შ', 'ش'),
1138
            'shch' => array('щ'),
1139
            'ss' => array('ß'),
1140
            'sx' => array('ŝ'),
1141
            'th' => array('þ', 'ϑ', 'ث', 'ذ', 'ظ'),
1142
            'ts' => array('ц', 'ც', 'წ'),
1143
            'ue' => array('ü'),
1144
            'uu' => array('ऊ'),
1145
            'ya' => array('я'),
1146
            'yu' => array('ю'),
1147
            'zh' => array('ж', 'ჟ', 'ژ'),
1148
            '(c)' => array('©'),
1149
            'A' => array(
1150
                'Á',
1151
                'À',
1152
                'Ả',
1153
                'Ã',
1154
                'Ạ',
1155
                'Ă',
1156
                'Ắ',
1157
                'Ằ',
1158
                'Ẳ',
1159
                'Ẵ',
1160
                'Ặ',
1161
                'Â',
1162
                'Ấ',
1163
                'Ầ',
1164
                'Ẩ',
1165
                'Ẫ',
1166
                'Ậ',
1167
                'Å',
1168
                'Ā',
1169
                'Ą',
1170
                'Α',
1171
                'Ά',
1172
                'Ἀ',
1173
                'Ἁ',
1174
                'Ἂ',
1175
                'Ἃ',
1176
                'Ἄ',
1177
                'Ἅ',
1178
                'Ἆ',
1179
                'Ἇ',
1180
                'ᾈ',
1181
                'ᾉ',
1182
                'ᾊ',
1183
                'ᾋ',
1184
                'ᾌ',
1185
                'ᾍ',
1186
                'ᾎ',
1187
                'ᾏ',
1188
                'Ᾰ',
1189
                'Ᾱ',
1190
                'Ὰ',
1191
                'Ά',
1192
                'ᾼ',
1193
                'А',
1194
                'Ǻ',
1195
                'Ǎ'
1196
            ),
1197
            'B' => array('Б', 'Β', 'ब'),
1198
            'C' => array('Ç', 'Ć', 'Č', 'Ĉ', 'Ċ'),
1199
            'D' => array('Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ'),
1200
            'E' => array(
1201
                'É',
1202
                'È',
1203
                'Ẻ',
1204
                'Ẽ',
1205
                'Ẹ',
1206
                'Ê',
1207
                'Ế',
1208
                'Ề',
1209
                'Ể',
1210
                'Ễ',
1211
                'Ệ',
1212
                'Ë',
1213
                'Ē',
1214
                'Ę',
1215
                'Ě',
1216
                'Ĕ',
1217
                'Ė',
1218
                'Ε',
1219
                'Έ',
1220
                'Ἐ',
1221
                'Ἑ',
1222
                'Ἒ',
1223
                'Ἓ',
1224
                'Ἔ',
1225
                'Ἕ',
1226
                'Έ',
1227
                'Ὲ',
1228
                'Е',
1229
                'Ё',
1230
                'Э',
1231
                'Є',
1232
                'Ə'
1233
            ),
1234
            'F' => array('Ф', 'Φ'),
1235
            'G' => array('Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ'),
1236
            'H' => array('Η', 'Ή', 'Ħ'),
1237
            'I' => array(
1238
                'Í',
1239
                'Ì',
1240
                'Ỉ',
1241
                'Ĩ',
1242
                'Ị',
1243
                'Î',
1244
                'Ï',
1245
                'Ī',
1246
                'Ĭ',
1247
                'Į',
1248
                'İ',
1249
                'Ι',
1250
                'Ί',
1251
                'Ϊ',
1252
                'Ἰ',
1253
                'Ἱ',
1254
                'Ἳ',
1255
                'Ἴ',
1256
                'Ἵ',
1257
                'Ἶ',
1258
                'Ἷ',
1259
                'Ῐ',
1260
                'Ῑ',
1261
                'Ὶ',
1262
                'Ί',
1263
                'И',
1264
                'І',
1265
                'Ї',
1266
                'Ǐ',
1267
                'ϒ'
1268
            ),
1269
            'K' => array('К', 'Κ'),
1270
            'L' => array('Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल'),
1271
            'M' => array('М', 'Μ'),
1272
            'N' => array('Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν'),
1273
            'O' => array(
1274
                'Ó',
1275
                'Ò',
1276
                'Ỏ',
1277
                'Õ',
1278
                'Ọ',
1279
                'Ô',
1280
                'Ố',
1281
                'Ồ',
1282
                'Ổ',
1283
                'Ỗ',
1284
                'Ộ',
1285
                'Ơ',
1286
                'Ớ',
1287
                'Ờ',
1288
                'Ở',
1289
                'Ỡ',
1290
                'Ợ',
1291
                'Ø',
1292
                'Ō',
1293
                'Ő',
1294
                'Ŏ',
1295
                'Ο',
1296
                'Ό',
1297
                'Ὀ',
1298
                'Ὁ',
1299
                'Ὂ',
1300
                'Ὃ',
1301
                'Ὄ',
1302
                'Ὅ',
1303
                'Ὸ',
1304
                'Ό',
1305
                'О',
1306
                'Θ',
1307
                'Ө',
1308
                'Ǒ',
1309
                'Ǿ'
1310
            ),
1311
            'P' => array('П', 'Π'),
1312
            'R' => array('Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ'),
1313
            'S' => array('Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ'),
1314
            'T' => array('Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ'),
1315
            'U' => array(
1316
                'Ú',
1317
                'Ù',
1318
                'Ủ',
1319
                'Ũ',
1320
                'Ụ',
1321
                'Ư',
1322
                'Ứ',
1323
                'Ừ',
1324
                'Ử',
1325
                'Ữ',
1326
                'Ự',
1327
                'Û',
1328
                'Ū',
1329
                'Ů',
1330
                'Ű',
1331
                'Ŭ',
1332
                'Ų',
1333
                'У',
1334
                'Ǔ',
1335
                'Ǖ',
1336
                'Ǘ',
1337
                'Ǚ',
1338
                'Ǜ'
1339
            ),
1340
            'V' => array('В'),
1341
            'W' => array('Ω', 'Ώ', 'Ŵ'),
1342
            'X' => array('Χ', 'Ξ'),
1343
            'Y' => array(
1344
                'Ý',
1345
                'Ỳ',
1346
                'Ỷ',
1347
                'Ỹ',
1348
                'Ỵ',
1349
                'Ÿ',
1350
                'Ῠ',
1351
                'Ῡ',
1352
                'Ὺ',
1353
                'Ύ',
1354
                'Ы',
1355
                'Й',
1356
                'Υ',
1357
                'Ϋ',
1358
                'Ŷ'
1359
            ),
1360
            'Z' => array('Ź', 'Ž', 'Ż', 'З', 'Ζ'),
1361
            'AE' => array('Ä', 'Æ', 'Ǽ'),
1362
            'CH' => array('Ч'),
1363
            'DJ' => array('Ђ'),
1364
            'DZ' => array('Џ'),
1365
            'GX' => array('Ĝ'),
1366
            'HX' => array('Ĥ'),
1367
            'IJ' => array('IJ'),
1368
            'JX' => array('Ĵ'),
1369
            'KH' => array('Х'),
1370
            'LJ' => array('Љ'),
1371
            'NJ' => array('Њ'),
1372
            'OE' => array('Ö', 'Œ'),
1373
            'PS' => array('Ψ'),
1374
            'SH' => array('Ш'),
1375
            'SHCH' => array('Щ'),
1376
            'SS' => array('ẞ'),
1377
            'TH' => array('Þ'),
1378
            'TS' => array('Ц'),
1379
            'UE' => array('Ü'),
1380
            'YA' => array('Я'),
1381
            'YU' => array('Ю'),
1382
            'ZH' => array('Ж'),
1383
            ' ' => array(
1384
                "\xC2\xA0",
1385
                "\xE2\x80\x80",
1386
                "\xE2\x80\x81",
1387
                "\xE2\x80\x82",
1388
                "\xE2\x80\x83",
1389
                "\xE2\x80\x84",
1390
                "\xE2\x80\x85",
1391
                "\xE2\x80\x86",
1392
                "\xE2\x80\x87",
1393
                "\xE2\x80\x88",
1394
                "\xE2\x80\x89",
1395
                "\xE2\x80\x8A",
1396
                "\xE2\x80\xAF",
1397
                "\xE2\x81\x9F",
1398
                "\xE3\x80\x80"
1399
            ),
1400
        );
1401
    }
1402
}
1403
if (!function_exists('charsArrayRegEx')) {
1404
    /**
1405
     * Returns regex to replacements for diacritics, German chars, and non ASCII chars.
1406
     *
1407
     * @return array An array of regex.
1408
     */
1409
    function charsArrayRegEx()
1410
    {
1411
        return array(
1412
            // maps German (umlauts) and other European characters onto two characters
1413
            // before just removing diacritics
1414
            "AE" => '/\x{00c4}/u', // umlaut Ä => AE
1415
            "OE" => '/\x{00d6}/u', // umlaut Ö => OE
1416
            "UE" => '/\x{00dc}/u', // umlaut Ü => UE
1417
            "ae" => '/\x{00e4}/u', // umlaut ä => ae
1418
            "oe" => '/\x{00f6}/u', // umlaut ö => oe
1419
            "ue" => '/\x{00fc}/u', // umlaut ü => ue
1420
            "ny" => '/\x{00f1}/u', // ñ => ny
1421
            "yu" => '/\x{00ff}/u', // ÿ => yu
1422
1423
            "" => '/\pM/u', // removes diacritics
1424
1425
            "ss" => '/\x{00df}/u', // maps German ß onto ss
1426
            "AE" => '/\x{00c6}/u', // Æ => AE
1427
            "ae" => '/\x{00e6}/u', // æ => ae
1428
            "IJ" => '/\x{0132}/u', // ? => IJ
1429
            "ij" => '/\x{0133}/u', // ? => ij
1430
            "OE" => '/\x{0152}/u', // Œ => OE
1431
            "oe" => '/\x{0153}/u', // œ => oe
1432
1433
            "D" => '/\x{00d0}/u', // Ð => D
1434
            "D" => '/\x{0110}/u', // Ð => D
1435
            "d" => '/\x{00f0}/u', // ð => d
1436
            "d" => '/\x{0111}/u', // d => d
1437
            "H" => '/\x{0126}/u', // H => H
1438
            "h" => '/\x{0127}/u', // h => h
1439
            "i" => '/\x{0131}/u', // i => i
1440
            "k" => '/\x{0138}/u', // ? => k
1441
            "L" => '/\x{013f}/u', // ? => L
1442
            "L" => '/\x{0141}/u', // L => L
1443
            "l" => '/\x{0140}/u', // ? => l
1444
            "l" => '/\x{0142}/u', // l => l
1445
            "N" => '/\x{014a}/u', // ? => N
1446
            "n" => '/\x{0149}/u', // ? => n
1447
            "n" => '/\x{014b}/u', // ? => n
1448
            "O" => '/\x{00d8}/u', // Ø => O
1449
            "o" => '/\x{00f8}/u', // ø => o
1450
            "s" => '/\x{017f}/u', // ? => s
1451
            "T" => '/\x{00de}/u', // Þ => T
1452
            "T" => '/\x{0166}/u', // T => T
1453
            "t" => '/\x{00fe}/u', // þ => t
1454
            "t" => '/\x{0167}/u', // t => t
1455
            
1456
            '' => '/[^\x20-\x7E]/u', // remove all non-ASCii characters
1457
            '' => '/[^\0-\x80]/u', // remove all non-ASCii characters
1458
        );
1459
    }
1460
}
1461