• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JBZoo / Utils / 7758887503

28 Jan 2024 08:37AM UTC coverage: 92.758% (-0.4%) from 93.158%
7758887503

push

github

web-flow
Update PHP 8.3 (#47)

14 of 14 new or added lines in 4 files covered. (100.0%)

8 existing lines in 3 files now uncovered.

1665 of 1795 relevant lines covered (92.76%)

41.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.76
/src/Slug.php
1
<?php
2

3
/**
4
 * JBZoo Toolbox - Utils.
5
 *
6
 * This file is part of the JBZoo Toolbox project.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT
11
 * @copyright  Copyright (C) JBZoo.com, All rights reserved.
12
 * @see        https://github.com/JBZoo/Utils
13
 */
14

15
declare(strict_types=1);
16

17
namespace JBZoo\Utils;
18

19
final class Slug
20
{
21
    // The map to convert characters to ASCII characters.
22
    public static array $maps = [
23
        'de' => [// German
24
            'Ä' => 'Ae',
25
            'Ö' => 'Oe',
26
            'Ü' => 'Ue',
27
            'ä' => 'ae',
28
            'ö' => 'oe',
29
            'ü' => 'ue',
30
            'ß' => 'ss',
31
            'ẞ' => 'SS',
32
        ],
33

34
        'latin' => [
35
            'À' => 'A',
36
            'Á' => 'A',
37
            'Â' => 'A',
38
            'Ã' => 'A',
39
            'Ä' => 'A',
40
            'Å' => 'A',
41
            'Ă' => 'A',
42
            'Æ' => 'AE',
43
            'Ç' => 'C',
44
            'È' => 'E',
45
            'É' => 'E',
46
            'Ê' => 'E',
47
            'Ë' => 'E',
48
            'Ì' => 'I',
49
            'Í' => 'I',
50
            'Î' => 'I',
51
            'Ï' => 'I',
52
            'Ð' => 'D',
53
            'Ñ' => 'N',
54
            'Ò' => 'O',
55
            'Ó' => 'O',
56
            'Ô' => 'O',
57
            'Õ' => 'O',
58
            'Ö' => 'O',
59
            'Ő' => 'O',
60
            'Ø' => 'O',
61
            'Ș' => 'S',
62
            'Ț' => 'T',
63
            'Ù' => 'U',
64
            'Ú' => 'U',
65
            'Û' => 'U',
66
            'Ü' => 'U',
67
            'Ű' => 'U',
68
            'Ý' => 'Y',
69
            'Þ' => 'TH',
70
            'ß' => 'ss',
71
            'à' => 'a',
72
            'á' => 'a',
73
            'â' => 'a',
74
            'ã' => 'a',
75
            'ä' => 'a',
76
            'å' => 'a',
77
            'ă' => 'a',
78
            'æ' => 'ae',
79
            'ç' => 'c',
80
            'è' => 'e',
81
            'é' => 'e',
82
            'ê' => 'e',
83
            'ë' => 'e',
84
            'ì' => 'i',
85
            'í' => 'i',
86
            'î' => 'i',
87
            'ï' => 'i',
88
            'ð' => 'd',
89
            'ñ' => 'n',
90
            'ò' => 'o',
91
            'ó' => 'o',
92
            'ô' => 'o',
93
            'õ' => 'o',
94
            'ö' => 'o',
95
            'ő' => 'o',
96
            'ø' => 'o',
97
            'ș' => 's',
98
            'ț' => 't',
99
            'ù' => 'u',
100
            'ú' => 'u',
101
            'û' => 'u',
102
            'ü' => 'u',
103
            'ű' => 'u',
104
            'ý' => 'y',
105
            'þ' => 'th',
106
            'ÿ' => 'y',
107
        ],
108

109
        'latin_symbols' => [
110
            '©' => '(c)',
111
        ],
112

113
        'el' => [// Greek
114
            'α' => 'a',
115
            'β' => 'b',
116
            'γ' => 'g',
117
            'δ' => 'd',
118
            'ε' => 'e',
119
            'ζ' => 'z',
120
            'η' => 'h',
121
            'θ' => '8',
122
            'ι' => 'i',
123
            'κ' => 'k',
124
            'λ' => 'l',
125
            'μ' => 'm',
126
            'ν' => 'n',
127
            'ξ' => '3',
128
            'ο' => 'o',
129
            'π' => 'p',
130
            'ρ' => 'r',
131
            'σ' => 's',
132
            'τ' => 't',
133
            'υ' => 'y',
134
            'φ' => 'f',
135
            'χ' => 'x',
136
            'ψ' => 'ps',
137
            'ω' => 'w',
138
            'ά' => 'a',
139
            'έ' => 'e',
140
            'ί' => 'i',
141
            'ό' => 'o',
142
            'ύ' => 'y',
143
            'ή' => 'h',
144
            'ώ' => 'w',
145
            'ς' => 's',
146
            'ϊ' => 'i',
147
            'ΰ' => 'y',
148
            'ϋ' => 'y',
149
            'ΐ' => 'i',
150
            'Α' => 'A',
151
            'Β' => 'B',
152
            'Γ' => 'G',
153
            'Δ' => 'D',
154
            'Ε' => 'E',
155
            'Ζ' => 'Z',
156
            'Η' => 'H',
157
            'Θ' => '8',
158
            'Ι' => 'I',
159
            'Κ' => 'K',
160
            'Λ' => 'L',
161
            'Μ' => 'M',
162
            'Ν' => 'N',
163
            'Ξ' => '3',
164
            'Ο' => 'O',
165
            'Π' => 'P',
166
            'Ρ' => 'R',
167
            'Σ' => 'S',
168
            'Τ' => 'T',
169
            'Υ' => 'Y',
170
            'Φ' => 'F',
171
            'Χ' => 'X',
172
            'Ψ' => 'PS',
173
            'Ω' => 'W',
174
            'Ά' => 'A',
175
            'Έ' => 'E',
176
            'Ί' => 'I',
177
            'Ό' => 'O',
178
            'Ύ' => 'Y',
179
            'Ή' => 'H',
180
            'Ώ' => 'W',
181
            'Ϊ' => 'I',
182
            'Ϋ' => 'Y',
183
        ],
184

185
        'tr' => [// Turkish
186
            'ş' => 's',
187
            'Ş' => 'S',
188
            'ı' => 'i',
189
            'İ' => 'I',
190
            'ç' => 'c',
191
            'Ç' => 'C',
192
            'ü' => 'u',
193
            'Ü' => 'U',
194
            'ö' => 'o',
195
            'Ö' => 'O',
196
            'ğ' => 'g',
197
            'Ğ' => 'G',
198
        ],
199

200
        'bg' => [// Bulgarian
201
            'Щ' => 'Sht',
202
            'Ш' => 'Sh',
203
            'Ч' => 'Ch',
204
            'Ц' => 'C',
205
            'Ю' => 'Yu',
206
            'Я' => 'Ya',
207
            'Ж' => 'J',
208
            'А' => 'A',
209
            'Б' => 'B',
210
            'В' => 'V',
211
            'Г' => 'G',
212
            'Д' => 'D',
213
            'Е' => 'E',
214
            'З' => 'Z',
215
            'И' => 'I',
216
            'Й' => 'Y',
217
            'К' => 'K',
218
            'Л' => 'L',
219
            'М' => 'M',
220
            'Н' => 'N',
221
            'О' => 'O',
222
            'П' => 'P',
223
            'Р' => 'R',
224
            'С' => 'S',
225
            'Т' => 'T',
226
            'У' => 'U',
227
            'Ф' => 'F',
228
            'Х' => 'H',
229
            'Ь' => '',
230
            'Ъ' => 'A',
231
            'щ' => 'sht',
232
            'ш' => 'sh',
233
            'ч' => 'ch',
234
            'ц' => 'c',
235
            'ю' => 'yu',
236
            'я' => 'ya',
237
            'ж' => 'j',
238
            'а' => 'a',
239
            'б' => 'b',
240
            'в' => 'v',
241
            'г' => 'g',
242
            'д' => 'd',
243
            'е' => 'e',
244
            'з' => 'z',
245
            'и' => 'i',
246
            'й' => 'y',
247
            'к' => 'k',
248
            'л' => 'l',
249
            'м' => 'm',
250
            'н' => 'n',
251
            'о' => 'o',
252
            'п' => 'p',
253
            'р' => 'r',
254
            'с' => 's',
255
            'т' => 't',
256
            'у' => 'u',
257
            'ф' => 'f',
258
            'х' => 'h',
259
            'ь' => '',
260
            'ъ' => 'a',
261
        ],
262

263
        'ru' => [// Russian
264
            'а' => 'a',
265
            'б' => 'b',
266
            'в' => 'v',
267
            'г' => 'g',
268
            'д' => 'd',
269
            'е' => 'e',
270
            'ё' => 'yo',
271
            'ж' => 'zh',
272
            'з' => 'z',
273
            'и' => 'i',
274
            'й' => 'j',
275
            'к' => 'k',
276
            'л' => 'l',
277
            'м' => 'm',
278
            'н' => 'n',
279
            'о' => 'o',
280
            'п' => 'p',
281
            'р' => 'r',
282
            'с' => 's',
283
            'т' => 't',
284
            'у' => 'u',
285
            'ф' => 'f',
286
            'х' => 'h',
287
            'ц' => 'c',
288
            'ч' => 'ch',
289
            'ш' => 'sh',
290
            'щ' => 'sh',
291
            'ъ' => '',
292
            'ы' => 'y',
293
            'ь' => '',
294
            'э' => 'e',
295
            'ю' => 'yu',
296
            'я' => 'ya',
297
            'А' => 'A',
298
            'Б' => 'B',
299
            'В' => 'V',
300
            'Г' => 'G',
301
            'Д' => 'D',
302
            'Е' => 'E',
303
            'Ё' => 'Yo',
304
            'Ж' => 'Zh',
305
            'З' => 'Z',
306
            'И' => 'I',
307
            'Й' => 'J',
308
            'К' => 'K',
309
            'Л' => 'L',
310
            'М' => 'M',
311
            'Н' => 'N',
312
            'О' => 'O',
313
            'П' => 'P',
314
            'Р' => 'R',
315
            'С' => 'S',
316
            'Т' => 'T',
317
            'У' => 'U',
318
            'Ф' => 'F',
319
            'Х' => 'H',
320
            'Ц' => 'C',
321
            'Ч' => 'Ch',
322
            'Ш' => 'Sh',
323
            'Щ' => 'Sh',
324
            'Ъ' => '',
325
            'Ы' => 'Y',
326
            'Ь' => '',
327
            'Э' => 'E',
328
            'Ю' => 'Yu',
329
            'Я' => 'Ya',
330
            '№' => '',
331
        ],
332

333
        'uk' => [// Ukrainian
334
            'Є' => 'Ye',
335
            'І' => 'I',
336
            'Ї' => 'Yi',
337
            'Ґ' => 'G',
338
            'є' => 'ye',
339
            'і' => 'i',
340
            'ї' => 'yi',
341
            'ґ' => 'g',
342
        ],
343

344
        'cs' => [// Czech
345
            'č' => 'c',
346
            'ď' => 'd',
347
            'ě' => 'e',
348
            'ň' => 'n',
349
            'ř' => 'r',
350
            'š' => 's',
351
            'ť' => 't',
352
            'ů' => 'u',
353
            'ž' => 'z',
354
            'Č' => 'C',
355
            'Ď' => 'D',
356
            'Ě' => 'E',
357
            'Ň' => 'N',
358
            'Ř' => 'R',
359
            'Š' => 'S',
360
            'Ť' => 'T',
361
            'Ů' => 'U',
362
            'Ž' => 'Z',
363
        ],
364

365
        'pl' => [// Polish
366
            'ą' => 'a',
367
            'ć' => 'c',
368
            'ę' => 'e',
369
            'ł' => 'l',
370
            'ń' => 'n',
371
            'ó' => 'o',
372
            'ś' => 's',
373
            'ź' => 'z',
374
            'ż' => 'z',
375
            'Ą' => 'A',
376
            'Ć' => 'C',
377
            'Ę' => 'e',
378
            'Ł' => 'L',
379
            'Ń' => 'N',
380
            'Ó' => 'O',
381
            'Ś' => 'S',
382
            'Ź' => 'Z',
383
            'Ż' => 'Z',
384
        ],
385

386
        'ro' => [// Romanian
387
            'ă' => 'a',
388
            'â' => 'a',
389
            'î' => 'i',
390
            'ș' => 's',
391
            'ț' => 't',
392
            'Ţ' => 'T',
393
            'ţ' => 't',
394
        ],
395

396
        'lv' => [// Latvian
397
            'ā' => 'a',
398
            'č' => 'c',
399
            'ē' => 'e',
400
            'ģ' => 'g',
401
            'ī' => 'i',
402
            'ķ' => 'k',
403
            'ļ' => 'l',
404
            'ņ' => 'n',
405
            'š' => 's',
406
            'ū' => 'u',
407
            'ž' => 'z',
408
            'Ā' => 'A',
409
            'Č' => 'C',
410
            'Ē' => 'E',
411
            'Ģ' => 'G',
412
            'Ī' => 'i',
413
            'Ķ' => 'k',
414
            'Ļ' => 'L',
415
            'Ņ' => 'N',
416
            'Š' => 'S',
417
            'Ū' => 'u',
418
            'Ž' => 'Z',
419
        ],
420

421
        'lt' => [// Lithuanian
422
            'ą' => 'a',
423
            'č' => 'c',
424
            'ę' => 'e',
425
            'ė' => 'e',
426
            'į' => 'i',
427
            'š' => 's',
428
            'ų' => 'u',
429
            'ū' => 'u',
430
            'ž' => 'z',
431
            'Ą' => 'A',
432
            'Č' => 'C',
433
            'Ę' => 'E',
434
            'Ė' => 'E',
435
            'Į' => 'I',
436
            'Š' => 'S',
437
            'Ų' => 'U',
438
            'Ū' => 'U',
439
            'Ž' => 'Z',
440
        ],
441

442
        'vn' => [// Vietnamese
443
            'Á' => 'A',
444
            'À' => 'A',
445
            'Ả' => 'A',
446
            'Ã' => 'A',
447
            'Ạ' => 'A',
448
            'Ă' => 'A',
449
            'Ắ' => 'A',
450
            'Ằ' => 'A',
451
            'Ẳ' => 'A',
452
            'Ẵ' => 'A',
453
            'Ặ' => 'A',
454
            'Â' => 'A',
455
            'Ấ' => 'A',
456
            'Ầ' => 'A',
457
            'Ẩ' => 'A',
458
            'Ẫ' => 'A',
459
            'Ậ' => 'A',
460
            'á' => 'a',
461
            'à' => 'a',
462
            'ả' => 'a',
463
            'ã' => 'a',
464
            'ạ' => 'a',
465
            'ă' => 'a',
466
            'ắ' => 'a',
467
            'ằ' => 'a',
468
            'ẳ' => 'a',
469
            'ẵ' => 'a',
470
            'ặ' => 'a',
471
            'â' => 'a',
472
            'ấ' => 'a',
473
            'ầ' => 'a',
474
            'ẩ' => 'a',
475
            'ẫ' => 'a',
476
            'ậ' => 'a',
477
            'É' => 'E',
478
            'È' => 'E',
479
            'Ẻ' => 'E',
480
            'Ẽ' => 'E',
481
            'Ẹ' => 'E',
482
            'Ê' => 'E',
483
            'Ế' => 'E',
484
            'Ề' => 'E',
485
            'Ể' => 'E',
486
            'Ễ' => 'E',
487
            'Ệ' => 'E',
488
            'é' => 'e',
489
            'è' => 'e',
490
            'ẻ' => 'e',
491
            'ẽ' => 'e',
492
            'ẹ' => 'e',
493
            'ê' => 'e',
494
            'ế' => 'e',
495
            'ề' => 'e',
496
            'ể' => 'e',
497
            'ễ' => 'e',
498
            'ệ' => 'e',
499
            'Í' => 'I',
500
            'Ì' => 'I',
501
            'Ỉ' => 'I',
502
            'Ĩ' => 'I',
503
            'Ị' => 'I',
504
            'í' => 'i',
505
            'ì' => 'i',
506
            'ỉ' => 'i',
507
            'ĩ' => 'i',
508
            'ị' => 'i',
509
            'Ó' => 'O',
510
            'Ò' => 'O',
511
            'Ỏ' => 'O',
512
            'Õ' => 'O',
513
            'Ọ' => 'O',
514
            'Ô' => 'O',
515
            'Ố' => 'O',
516
            'Ồ' => 'O',
517
            'Ổ' => 'O',
518
            'Ỗ' => 'O',
519
            'Ộ' => 'O',
520
            'Ơ' => 'O',
521
            'Ớ' => 'O',
522
            'Ờ' => 'O',
523
            'Ở' => 'O',
524
            'Ỡ' => 'O',
525
            'Ợ' => 'O',
526
            'ó' => 'o',
527
            'ò' => 'o',
528
            'ỏ' => 'o',
529
            'õ' => 'o',
530
            'ọ' => 'o',
531
            'ô' => 'o',
532
            'ố' => 'o',
533
            'ồ' => 'o',
534
            'ổ' => 'o',
535
            'ỗ' => 'o',
536
            'ộ' => 'o',
537
            'ơ' => 'o',
538
            'ớ' => 'o',
539
            'ờ' => 'o',
540
            'ở' => 'o',
541
            'ỡ' => 'o',
542
            'ợ' => 'o',
543
            'Ú' => 'U',
544
            'Ù' => 'U',
545
            'Ủ' => 'U',
546
            'Ũ' => 'U',
547
            'Ụ' => 'U',
548
            'Ư' => 'U',
549
            'Ứ' => 'U',
550
            'Ừ' => 'U',
551
            'Ử' => 'U',
552
            'Ữ' => 'U',
553
            'Ự' => 'U',
554
            'ú' => 'u',
555
            'ù' => 'u',
556
            'ủ' => 'u',
557
            'ũ' => 'u',
558
            'ụ' => 'u',
559
            'ư' => 'u',
560
            'ứ' => 'u',
561
            'ừ' => 'u',
562
            'ử' => 'u',
563
            'ữ' => 'u',
564
            'ự' => 'u',
565
            'Ý' => 'Y',
566
            'Ỳ' => 'Y',
567
            'Ỷ' => 'Y',
568
            'Ỹ' => 'Y',
569
            'Ỵ' => 'Y',
570
            'ý' => 'y',
571
            'ỳ' => 'y',
572
            'ỷ' => 'y',
573
            'ỹ' => 'y',
574
            'ỵ' => 'y',
575
            'Đ' => 'D',
576
            'đ' => 'd',
577
        ],
578

579
        'ar' => [// Arabic
580
            'أ' => 'a',
581
            'ب' => 'b',
582
            'ت' => 't',
583
            'ث' => 'th',
584
            'ج' => 'g',
585
            'ح' => 'h',
586
            'خ' => 'kh',
587
            'د' => 'd',
588
            'ذ' => 'th',
589
            'ر' => 'r',
590
            'ز' => 'z',
591
            'س' => 's',
592
            'ش' => 'sh',
593
            'ص' => 's',
594
            'ض' => 'd',
595
            'ط' => 't',
596
            'ظ' => 'th',
597
            'ع' => 'aa',
598
            'غ' => 'gh',
599
            'ف' => 'f',
600
            'ق' => 'k',
601
            'ك' => 'k',
602
            'ل' => 'l',
603
            'م' => 'm',
604
            'ن' => 'n',
605
            'ه' => 'h',
606
            'و' => 'o',
607
            'ي' => 'y',
608
        ],
609

610
        'sr' => [// Serbian
611
            'ђ' => 'dj',
612
            'ј' => 'j',
613
            'љ' => 'lj',
614
            'њ' => 'nj',
615
            'ћ' => 'c',
616
            'џ' => 'dz',
617
            'đ' => 'dj',
618
            'Ђ' => 'Dj',
619
            'Ј' => 'j',
620
            'Љ' => 'Lj',
621
            'Њ' => 'Nj',
622
            'Ћ' => 'C',
623
            'Џ' => 'Dz',
624
            'Đ' => 'Dj',
625
        ],
626

627
        'az' => [// Azerbaijani
628
            'ç' => 'c',
629
            'ə' => 'e',
630
            'ğ' => 'g',
631
            'ı' => 'i',
632
            'ö' => 'o',
633
            'ş' => 's',
634
            'ü' => 'u',
635
            'Ç' => 'C',
636
            'Ə' => 'E',
637
            'Ğ' => 'G',
638
            'İ' => 'I',
639
            'Ö' => 'O',
640
            'Ş' => 'S',
641
            'Ü' => 'U',
642
        ],
643
    ];
644

645
    /** The character map. */
646
    private static array $map = [];
647

648
    /** The character list as a string. */
649
    private static string $chars = '';
650

651
    /** The character list as a regular expression. */
652
    private static string $regex = '';
653

654
    /** The current language. */
655
    private static string $language = '';
656

657
    /**
658
     * Converts any accent characters to their equivalent normal characters and converts any other non-alphanumeric
659
     * characters to dashes, then converts any sequence of two or more dashes to a single dash. This function generates
660
     * slugs safe for use as URLs, and if you pass true as the second parameter, it will create strings safe for
661
     * use as CSS classes or IDs.
662
     * @param null|string $string    A string to convert to a slug
663
     * @param string      $separator The string to separate words with
664
     * @param bool        $cssMode   Whether to generate strings safe for CSS classes/IDs (Default to false)
665
     */
666
    public static function filter(?string $string, string $separator = '-', bool $cssMode = false): string
667
    {
668
        $slug = (string)\preg_replace('/([^a-z0-9]+)/', $separator, \strtolower(self::removeAccents((string)$string)));
24✔
669
        $slug = \trim($slug, $separator);
24✔
670

671
        if ($cssMode) {
24✔
672
            $firstLetter = (int)$slug[0];
6✔
673
            $digits      = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];
6✔
674
            if (isset($digits[$firstLetter])) {
6✔
675
                $slug = $digits[$firstLetter] . $separator . \substr($slug, 1);
6✔
676
            }
677
        }
678

679
        return $slug;
24✔
680
    }
681

682
    /**
683
     * Checks to see if a string is utf8 encoded.
684
     * NOTE: This function checks for 5-Byte sequences, UTF8 has Bytes Sequences with a maximum length of 4.
685
     * Written by Tony Ferrara <http://blog.ircmaxwell.com>.
686
     * @param string $string The string to be checked
687
     */
688
    public static function seemsUTF8(string $string): bool
689
    {
690
        if (Str::isMBString()) {
12✔
691
            // If mbstring is available, this is significantly faster than
692
            // using PHP regexps.
693
            return \mb_check_encoding($string, Str::$encoding);
12✔
694
        }
695

696
        return self::seemsUtf8Regex($string);
×
697
    }
698

699
    /**
700
     * Transliterates characters to their ASCII equivalents.
701
     * Part of the URLify.php Project <https://github.com/jbroadway/urlify/>.
702
     * @see https://github.com/jbroadway/urlify/blob/master/URLify.php
703
     * @param  string $text     Text that might have not-ASCII characters
704
     * @param  string $language specifies a priority for a specific language
705
     * @return string Filtered string with replaced "nice" characters
706
     */
707
    public static function downCode(string $text, string $language = ''): string
708
    {
709
        self::initLanguageMap($language);
12✔
710

711
        if (self::$regex !== '' && self::seemsUTF8($text)) {
12✔
712
            if (\preg_match_all(self::$regex, $text, $matches) > 0) {
12✔
713
                $matchesCount = \count($matches[0]);
12✔
714

715
                /** @noinspection ForeachInvariantsInspection */
716
                for ($i = 0; $i < $matchesCount; $i++) {
12✔
717
                    $char = $matches[0][$i];
12✔
718

719
                    if (\array_key_exists($char, self::$map)) {
12✔
720
                        $text = \str_replace($char, self::$map[$char], $text);
12✔
721
                    }
722
                }
723
            }
724
        } else {
725
            // Not a UTF-8 string so we assume its ISO-8859-1
726
            $search = "\x80\x83\x8a\x8e\x9a\x9e\x9f\xa2\xa5\xb5\xc0\xc1\xc2\xc3\xc4\xc5\xc7\xc8\xc9\xca\xcb\xcc\xcd";
6✔
727
            $search .= "\xce\xcf\xd1\xd2\xd3\xd4\xd5\xd6\xd8\xd9\xda\xdb\xdc\xdd\xe0\xe1\xe2\xe3\xe4\xe5\xe7\xe8\xe9";
6✔
728
            $search .= "\xea\xeb\xec\xed\xee\xef\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xff";
6✔
729
            $text = \strtr($text, $search, 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy');
6✔
730

731
            // These latin characters should be represented by two characters, so
732
            // we can't use strtr
733
            $complexSearch  = ["\x8c", "\x9c", "\xc6", "\xd0", "\xde", "\xdf", "\xe6", "\xf0", "\xfe"];
6✔
734
            $complexReplace = ['OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'];
6✔
735
            $text           = \str_replace($complexSearch, $complexReplace, $text);
6✔
736
        }
737

738
        return $text;
12✔
739
    }
740

741
    /**
742
     * Converts all accent characters to ASCII characters.
743
     * If there are no accent characters, then the string given is just returned.
744
     * @param  string $string   Text that might have accent characters
745
     * @param  string $language specifies a priority for a specific language
746
     * @return string Filtered  string with replaced "nice" characters
747
     */
748
    public static function removeAccents(string $string, string $language = ''): string
749
    {
750
        if (\preg_match('/[\x80-\xff]/', $string) === 0) {
42✔
751
            return $string;
30✔
752
        }
753

754
        return self::downCode($string, $language);
12✔
755
    }
756

757
    /**
758
     * Initializes the character map.
759
     * Part of the URLify.php Project <https://github.com/jbroadway/urlify/>.
760
     * @see https://github.com/jbroadway/urlify/blob/master/URLify.php
761
     */
762
    private static function initLanguageMap(string $language = ''): void
763
    {
764
        if ((isStrEmpty($language) || $language === self::$language) && \count(self::$map) > 0) {
12✔
765
            return;
6✔
766
        }
767

768
        // Is a specific map associated with $language?
769

770
        if (\array_key_exists($language, self::$maps) && \is_array(self::$maps[$language])) {
12✔
771
            // Move this map to end. This means it will have priority over others
772
            $langMap = self::$maps[$language];
6✔
773
            unset(self::$maps[$language]);
6✔
774
            self::$maps[$language] = $langMap;
6✔
775
        }
776

777
        // Reset static vars
778
        self::$language = $language;
12✔
779
        self::$map      = [];
12✔
780
        self::$chars    = '';
12✔
781

782
        foreach (self::$maps as $map) {
12✔
783
            foreach ((array)$map as $orig => $conv) {
12✔
784
                self::$map[$orig] = $conv;
12✔
785
                self::$chars .= $orig;
12✔
786
            }
787
        }
788

789
        self::$regex = '/[' . self::$chars . ']/u';
12✔
790
    }
791

792
    /**
793
     * A non-Mbstring UTF-8 checker.
794
     * @see http://stackoverflow.com/a/11709412/430062
795
     */
796
    private static function seemsUtf8Regex(string $string): bool
797
    {
798
        $regex = '/(
×
799
            [\xC0-\xC1]                                                         # Invalid UTF-8 Bytes
800
            | [\xF5-\xFF]                                                       # Invalid UTF-8 Bytes
801
            | \xE0[\x80-\x9F]                                                   # Overlong encoding of prior code point
802
            | \xF0[\x80-\x8F]                                                   # Overlong encoding of prior code point
803
            | [\xC2-\xDF](?![\x80-\xBF])                                        # Invalid UTF-8 Sequence Start
804
            | [\xE0-\xEF](?![\x80-\xBF]{2})                                     # Invalid UTF-8 Sequence Start
805
            | [\xF0-\xF4](?![\x80-\xBF]{3})                                     # Invalid UTF-8 Sequence Start
806
            | (?<=[\x0-\x7F\xF5-\xFF])[\x80-\xBF]                               # Invalid UTF-8 Sequence Middle
UNCOV
807
            | (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|'
×
UNCOV
808
            . '[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF]     # Overlong Sequence
×
809
            | (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF])                        # Short 3 byte sequence
810
            | (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2})                     # Short 4 byte sequence
811
            | (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF])             # Short 4 byte sequence (2)
UNCOV
812
        )/x';
×
813

814
        return \preg_match($regex, $string) === 0;
×
815
    }
816
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc