Iri   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 695
Duplicated Lines 0 %

Test Coverage

Coverage 80.65%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 13
eloc 645
c 1
b 0
f 0
dl 0
loc 695
ccs 25
cts 31
cp 0.8065
rs 9.955

3 Methods

Rating   Name   Duplication   Size   Complexity  
B unicodeNextChar() 0 21 7
A validationError() 0 8 2
B unicodeValidationError() 0 640 4
1
<?php
2
3
namespace Swaggest\JsonSchema\Constraint\Format;
4
5
class Iri
6
{
7
8
    /**
9
     * @param string $data
10
     * @param int $options
11
     * @return null|string
12
     */
13 16
    public static function validationError($data, $options = Uri::IS_SCHEME_REQUIRED)
14
    {
15 16
        $error = Iri::unicodeValidationError($data, $sanitized);
16 16
        if ($error !== null) {
17
            return $error;
18
        }
19
20 16
        return Uri::validationError($sanitized, $options);
21
    }
22
23
24
    /**
25
     * @see http://www.unicode.org/faq/idn.html
26
     * @see https://gist.github.com/rxu/0660eef7a2f9e7992db6
27
     * @param string $data
28
     * @param string $sanitized
29
     * @return null|string
30
     */
31 20
    public static function unicodeValidationError($data, &$sanitized = null)
32
    {
33 20
        static $excluded = array(
34
            "\xD9\x80" => '\u0640',
35
            "\xDF\xBA" => '\u07FA',
36
            "\xE3\x80\xAE" => '\u302E',
37
            "\xE3\x80\xAF" => '\u302F',
38
            "\xE3\x80\xB1" => '\u3031',
39
            "\xE3\x80\xB2" => '\u3032',
40
            "\xE3\x80\xB3" => '\u3033',
41
            "\xE3\x80\xB4" => '\u3034',
42
            "\xE3\x80\xB5" => '\u3035',
43
            "\xE3\x80\xBB" => '\u303B',
44
45
            // Remove characters used for archaic Hangul (Korean) - \p{HST=L} and \p{HST=V}
46
            // as per http://unicode.org/Public/UNIDATA/HangulSyllableType.txt
47
            "\xE1\x84\x80" => '\u1100',
48
            "\xE1\x84\x81" => '\u1101',
49
            "\xE1\x84\x82" => '\u1102',
50
            "\xE1\x84\x83" => '\u1103',
51
            "\xE1\x84\x84" => '\u1104',
52
            "\xE1\x84\x85" => '\u1105',
53
            "\xE1\x84\x86" => '\u1106',
54
            "\xE1\x84\x87" => '\u1107',
55
            "\xE1\x84\x88" => '\u1108',
56
            "\xE1\x84\x89" => '\u1109',
57
            "\xE1\x84\x8A" => '\u110a',
58
            "\xE1\x84\x8B" => '\u110b',
59
            "\xE1\x84\x8C" => '\u110c',
60
            "\xE1\x84\x8D" => '\u110d',
61
            "\xE1\x84\x8E" => '\u110e',
62
            "\xE1\x84\x8F" => '\u110f',
63
            "\xE1\x84\x90" => '\u1110',
64
            "\xE1\x84\x91" => '\u1111',
65
            "\xE1\x84\x92" => '\u1112',
66
            "\xE1\x84\x93" => '\u1113',
67
            "\xE1\x84\x94" => '\u1114',
68
            "\xE1\x84\x95" => '\u1115',
69
            "\xE1\x84\x96" => '\u1116',
70
            "\xE1\x84\x97" => '\u1117',
71
            "\xE1\x84\x98" => '\u1118',
72
            "\xE1\x84\x99" => '\u1119',
73
            "\xE1\x84\x9A" => '\u111a',
74
            "\xE1\x84\x9B" => '\u111b',
75
            "\xE1\x84\x9C" => '\u111c',
76
            "\xE1\x84\x9D" => '\u111d',
77
            "\xE1\x84\x9E" => '\u111e',
78
            "\xE1\x84\x9F" => '\u111f',
79
            "\xE1\x84\xA0" => '\u1120',
80
            "\xE1\x84\xA1" => '\u1121',
81
            "\xE1\x84\xA2" => '\u1122',
82
            "\xE1\x84\xA3" => '\u1123',
83
            "\xE1\x84\xA4" => '\u1124',
84
            "\xE1\x84\xA5" => '\u1125',
85
            "\xE1\x84\xA6" => '\u1126',
86
            "\xE1\x84\xA7" => '\u1127',
87
            "\xE1\x84\xA8" => '\u1128',
88
            "\xE1\x84\xA9" => '\u1129',
89
            "\xE1\x84\xAA" => '\u112a',
90
            "\xE1\x84\xAB" => '\u112b',
91
            "\xE1\x84\xAC" => '\u112c',
92
            "\xE1\x84\xAD" => '\u112d',
93
            "\xE1\x84\xAE" => '\u112e',
94
            "\xE1\x84\xAF" => '\u112f',
95
            "\xE1\x84\xB0" => '\u1130',
96
            "\xE1\x84\xB1" => '\u1131',
97
            "\xE1\x84\xB2" => '\u1132',
98
            "\xE1\x84\xB3" => '\u1133',
99
            "\xE1\x84\xB4" => '\u1134',
100
            "\xE1\x84\xB5" => '\u1135',
101
            "\xE1\x84\xB6" => '\u1136',
102
            "\xE1\x84\xB7" => '\u1137',
103
            "\xE1\x84\xB8" => '\u1138',
104
            "\xE1\x84\xB9" => '\u1139',
105
            "\xE1\x84\xBA" => '\u113a',
106
            "\xE1\x84\xBB" => '\u113b',
107
            "\xE1\x84\xBC" => '\u113c',
108
            "\xE1\x84\xBD" => '\u113d',
109
            "\xE1\x84\xBE" => '\u113e',
110
            "\xE1\x84\xBF" => '\u113f',
111
            "\xE1\x85\x80" => '\u1140',
112
            "\xE1\x85\x81" => '\u1141',
113
            "\xE1\x85\x82" => '\u1142',
114
            "\xE1\x85\x83" => '\u1143',
115
            "\xE1\x85\x84" => '\u1144',
116
            "\xE1\x85\x85" => '\u1145',
117
            "\xE1\x85\x86" => '\u1146',
118
            "\xE1\x85\x87" => '\u1147',
119
            "\xE1\x85\x88" => '\u1148',
120
            "\xE1\x85\x89" => '\u1149',
121
            "\xE1\x85\x8A" => '\u114a',
122
            "\xE1\x85\x8B" => '\u114b',
123
            "\xE1\x85\x8C" => '\u114c',
124
            "\xE1\x85\x8D" => '\u114d',
125
            "\xE1\x85\x8E" => '\u114e',
126
            "\xE1\x85\x8F" => '\u114f',
127
            "\xE1\x85\x90" => '\u1150',
128
            "\xE1\x85\x91" => '\u1151',
129
            "\xE1\x85\x92" => '\u1152',
130
            "\xE1\x85\x93" => '\u1153',
131
            "\xE1\x85\x94" => '\u1154',
132
            "\xE1\x85\x95" => '\u1155',
133
            "\xE1\x85\x96" => '\u1156',
134
            "\xE1\x85\x97" => '\u1157',
135
            "\xE1\x85\x98" => '\u1158',
136
            "\xE1\x85\x99" => '\u1159',
137
            "\xE1\x85\x9A" => '\u115a',
138
            "\xE1\x85\x9B" => '\u115b',
139
            "\xE1\x85\x9C" => '\u115c',
140
            "\xE1\x85\x9D" => '\u115d',
141
            "\xE1\x85\x9E" => '\u115e',
142
            "\xE1\x85\x9F" => '\u115f',
143
            "\xEA\xA5\xA0" => '\ua960',
144
            "\xEA\xA5\xA1" => '\ua961',
145
            "\xEA\xA5\xA2" => '\ua962',
146
            "\xEA\xA5\xA3" => '\ua963',
147
            "\xEA\xA5\xA4" => '\ua964',
148
            "\xEA\xA5\xA5" => '\ua965',
149
            "\xEA\xA5\xA6" => '\ua966',
150
            "\xEA\xA5\xA7" => '\ua967',
151
            "\xEA\xA5\xA8" => '\ua968',
152
            "\xEA\xA5\xA9" => '\ua969',
153
            "\xEA\xA5\xAA" => '\ua96a',
154
            "\xEA\xA5\xAB" => '\ua96b',
155
            "\xEA\xA5\xAC" => '\ua96c',
156
            "\xEA\xA5\xAD" => '\ua96d',
157
            "\xEA\xA5\xAE" => '\ua96e',
158
            "\xEA\xA5\xAF" => '\ua96f',
159
            "\xEA\xA5\xB0" => '\ua970',
160
            "\xEA\xA5\xB1" => '\ua971',
161
            "\xEA\xA5\xB2" => '\ua972',
162
            "\xEA\xA5\xB3" => '\ua973',
163
            "\xEA\xA5\xB4" => '\ua974',
164
            "\xEA\xA5\xB5" => '\ua975',
165
            "\xEA\xA5\xB6" => '\ua976',
166
            "\xEA\xA5\xB7" => '\ua977',
167
            "\xEA\xA5\xB8" => '\ua978',
168
            "\xEA\xA5\xB9" => '\ua979',
169
            "\xEA\xA5\xBA" => '\ua97a',
170
            "\xEA\xA5\xBB" => '\ua97b',
171
            "\xEA\xA5\xBC" => '\ua97c',
172
            "\xE1\x85\xA0" => '\u1160',
173
            "\xE1\x85\xA1" => '\u1161',
174
            "\xE1\x85\xA2" => '\u1162',
175
            "\xE1\x85\xA3" => '\u1163',
176
            "\xE1\x85\xA4" => '\u1164',
177
            "\xE1\x85\xA5" => '\u1165',
178
            "\xE1\x85\xA6" => '\u1166',
179
            "\xE1\x85\xA7" => '\u1167',
180
            "\xE1\x85\xA8" => '\u1168',
181
            "\xE1\x85\xA9" => '\u1169',
182
            "\xE1\x85\xAA" => '\u116a',
183
            "\xE1\x85\xAB" => '\u116b',
184
            "\xE1\x85\xAC" => '\u116c',
185
            "\xE1\x85\xAD" => '\u116d',
186
            "\xE1\x85\xAE" => '\u116e',
187
            "\xE1\x85\xAF" => '\u116f',
188
            "\xE1\x85\xB0" => '\u1170',
189
            "\xE1\x85\xB1" => '\u1171',
190
            "\xE1\x85\xB2" => '\u1172',
191
            "\xE1\x85\xB3" => '\u1173',
192
            "\xE1\x85\xB4" => '\u1174',
193
            "\xE1\x85\xB5" => '\u1175',
194
            "\xE1\x85\xB6" => '\u1176',
195
            "\xE1\x85\xB7" => '\u1177',
196
            "\xE1\x85\xB8" => '\u1178',
197
            "\xE1\x85\xB9" => '\u1179',
198
            "\xE1\x85\xBA" => '\u117a',
199
            "\xE1\x85\xBB" => '\u117b',
200
            "\xE1\x85\xBC" => '\u117c',
201
            "\xE1\x85\xBD" => '\u117d',
202
            "\xE1\x85\xBE" => '\u117e',
203
            "\xE1\x85\xBF" => '\u117f',
204
            "\xE1\x86\x80" => '\u1180',
205
            "\xE1\x86\x81" => '\u1181',
206
            "\xE1\x86\x82" => '\u1182',
207
            "\xE1\x86\x83" => '\u1183',
208
            "\xE1\x86\x84" => '\u1184',
209
            "\xE1\x86\x85" => '\u1185',
210
            "\xE1\x86\x86" => '\u1186',
211
            "\xE1\x86\x87" => '\u1187',
212
            "\xE1\x86\x88" => '\u1188',
213
            "\xE1\x86\x89" => '\u1189',
214
            "\xE1\x86\x8A" => '\u118a',
215
            "\xE1\x86\x8B" => '\u118b',
216
            "\xE1\x86\x8C" => '\u118c',
217
            "\xE1\x86\x8D" => '\u118d',
218
            "\xE1\x86\x8E" => '\u118e',
219
            "\xE1\x86\x8F" => '\u118f',
220
            "\xE1\x86\x90" => '\u1190',
221
            "\xE1\x86\x91" => '\u1191',
222
            "\xE1\x86\x92" => '\u1192',
223
            "\xE1\x86\x93" => '\u1193',
224
            "\xE1\x86\x94" => '\u1194',
225
            "\xE1\x86\x95" => '\u1195',
226
            "\xE1\x86\x96" => '\u1196',
227
            "\xE1\x86\x97" => '\u1197',
228
            "\xE1\x86\x98" => '\u1198',
229
            "\xE1\x86\x99" => '\u1199',
230
            "\xE1\x86\x9A" => '\u119a',
231
            "\xE1\x86\x9B" => '\u119b',
232
            "\xE1\x86\x9C" => '\u119c',
233
            "\xE1\x86\x9D" => '\u119d',
234
            "\xE1\x86\x9E" => '\u119e',
235
            "\xE1\x86\x9F" => '\u119f',
236
            "\xE1\x86\xA0" => '\u11a0',
237
            "\xE1\x86\xA1" => '\u11a1',
238
            "\xE1\x86\xA2" => '\u11a2',
239
            "\xE1\x86\xA3" => '\u11a3',
240
            "\xE1\x86\xA4" => '\u11a4',
241
            "\xE1\x86\xA5" => '\u11a5',
242
            "\xE1\x86\xA6" => '\u11a6',
243
            "\xE1\x86\xA7" => '\u11a7',
244
            "\xED\x9E\xB0" => '\ud7b0',
245
            "\xED\x9E\xB1" => '\ud7b1',
246
            "\xED\x9E\xB2" => '\ud7b2',
247
            "\xED\x9E\xB3" => '\ud7b3',
248
            "\xED\x9E\xB4" => '\ud7b4',
249
            "\xED\x9E\xB5" => '\ud7b5',
250
            "\xED\x9E\xB6" => '\ud7b6',
251
            "\xED\x9E\xB7" => '\ud7b7',
252
            "\xED\x9E\xB8" => '\ud7b8',
253
            "\xED\x9E\xB9" => '\ud7b9',
254
            "\xED\x9E\xBA" => '\ud7ba',
255
            "\xED\x9E\xBB" => '\ud7bb',
256
            "\xED\x9E\xBC" => '\ud7bc',
257
            "\xED\x9E\xBD" => '\ud7bd',
258
            "\xED\x9E\xBE" => '\ud7be',
259
            "\xED\x9E\xBF" => '\ud7bf',
260
            "\xED\x9F\x80" => '\ud7c0',
261
            "\xED\x9F\x81" => '\ud7c1',
262
            "\xED\x9F\x82" => '\ud7c2',
263
            "\xED\x9F\x83" => '\ud7c3',
264
            "\xED\x9F\x84" => '\ud7c4',
265
            "\xED\x9F\x85" => '\ud7c5',
266
            "\xED\x9F\x86" => '\ud7c6',
267
268
            // Remove three blocks of technical or archaic symbols.
269
            // \p{block=Combining_Diacritical_Marks_For_Symbols}
270
            "\xE2\x83\x90" => '\u20d0',
271
            "\xE2\x83\x91" => '\u20d1',
272
            "\xE2\x83\x92" => '\u20d2',
273
            "\xE2\x83\x93" => '\u20d3',
274
            "\xE2\x83\x94" => '\u20d4',
275
            "\xE2\x83\x95" => '\u20d5',
276
            "\xE2\x83\x96" => '\u20d6',
277
            "\xE2\x83\x97" => '\u20d7',
278
            "\xE2\x83\x98" => '\u20d8',
279
            "\xE2\x83\x99" => '\u20d9',
280
            "\xE2\x83\x9A" => '\u20da',
281
            "\xE2\x83\x9B" => '\u20db',
282
            "\xE2\x83\x9C" => '\u20dc',
283
            "\xE2\x83\x9D" => '\u20dd',
284
            "\xE2\x83\x9E" => '\u20de',
285
            "\xE2\x83\x9F" => '\u20df',
286
            "\xE2\x83\xA0" => '\u20e0',
287
            "\xE2\x83\xA1" => '\u20e1',
288
            "\xE2\x83\xA2" => '\u20e2',
289
            "\xE2\x83\xA3" => '\u20e3',
290
            "\xE2\x83\xA4" => '\u20e4',
291
            "\xE2\x83\xA5" => '\u20e5',
292
            "\xE2\x83\xA6" => '\u20e6',
293
            "\xE2\x83\xA7" => '\u20e7',
294
            "\xE2\x83\xA8" => '\u20e8',
295
            "\xE2\x83\xA9" => '\u20e9',
296
            "\xE2\x83\xAA" => '\u20ea',
297
            "\xE2\x83\xAB" => '\u20eb',
298
            "\xE2\x83\xAC" => '\u20ec',
299
            "\xE2\x83\xAD" => '\u20ed',
300
            "\xE2\x83\xAE" => '\u20ee',
301
            "\xE2\x83\xAF" => '\u20ef',
302
            "\xE2\x83\xB0" => '\u20f0',
303
            "\xE2\x83\xB1" => '\u20f1',
304
            "\xE2\x83\xB2" => '\u20f2',
305
            "\xE2\x83\xB3" => '\u20f3',
306
            "\xE2\x83\xB4" => '\u20f4',
307
            "\xE2\x83\xB5" => '\u20f5',
308
            "\xE2\x83\xB6" => '\u20f6',
309
            "\xE2\x83\xB7" => '\u20f7',
310
            "\xE2\x83\xB8" => '\u20f8',
311
            "\xE2\x83\xB9" => '\u20f9',
312
            "\xE2\x83\xBA" => '\u20fa',
313
            "\xE2\x83\xBB" => '\u20fb',
314
            "\xE2\x83\xBC" => '\u20fc',
315
            "\xE2\x83\xBD" => '\u20fd',
316
            "\xE2\x83\xBE" => '\u20fe',
317
            "\xE2\x83\xBF" => '\u20ff',
318
319
            // \p{block=Musical_Symbols}
320
            "\xE1\xB4\x90\x30" => '\u1d100',
321
            "\xE1\xB4\x90\x31" => '\u1d101',
322
            "\xE1\xB4\x90\x32" => '\u1d102',
323
            "\xE1\xB4\x90\x33" => '\u1d103',
324
            "\xE1\xB4\x90\x34" => '\u1d104',
325
            "\xE1\xB4\x90\x35" => '\u1d105',
326
            "\xE1\xB4\x90\x36" => '\u1d106',
327
            "\xE1\xB4\x90\x37" => '\u1d107',
328
            "\xE1\xB4\x90\x38" => '\u1d108',
329
            "\xE1\xB4\x90\x39" => '\u1d109',
330
            "\xE1\xB4\x90\x61" => '\u1d10a',
331
            "\xE1\xB4\x90\x62" => '\u1d10b',
332
            "\xE1\xB4\x90\x63" => '\u1d10c',
333
            "\xE1\xB4\x90\x64" => '\u1d10d',
334
            "\xE1\xB4\x90\x65" => '\u1d10e',
335
            "\xE1\xB4\x90\x66" => '\u1d10f',
336
            "\xE1\xB4\x91\x30" => '\u1d110',
337
            "\xE1\xB4\x91\x31" => '\u1d111',
338
            "\xE1\xB4\x91\x32" => '\u1d112',
339
            "\xE1\xB4\x91\x33" => '\u1d113',
340
            "\xE1\xB4\x91\x34" => '\u1d114',
341
            "\xE1\xB4\x91\x35" => '\u1d115',
342
            "\xE1\xB4\x91\x36" => '\u1d116',
343
            "\xE1\xB4\x91\x37" => '\u1d117',
344
            "\xE1\xB4\x91\x38" => '\u1d118',
345
            "\xE1\xB4\x91\x39" => '\u1d119',
346
            "\xE1\xB4\x91\x61" => '\u1d11a',
347
            "\xE1\xB4\x91\x62" => '\u1d11b',
348
            "\xE1\xB4\x91\x63" => '\u1d11c',
349
            "\xE1\xB4\x91\x64" => '\u1d11d',
350
            "\xE1\xB4\x91\x65" => '\u1d11e',
351
            "\xE1\xB4\x91\x66" => '\u1d11f',
352
            "\xE1\xB4\x92\x30" => '\u1d120',
353
            "\xE1\xB4\x92\x31" => '\u1d121',
354
            "\xE1\xB4\x92\x32" => '\u1d122',
355
            "\xE1\xB4\x92\x33" => '\u1d123',
356
            "\xE1\xB4\x92\x34" => '\u1d124',
357
            "\xE1\xB4\x92\x35" => '\u1d125',
358
            "\xE1\xB4\x92\x36" => '\u1d126',
359
            "\xE1\xB4\x92\x37" => '\u1d127',
360
            "\xE1\xB4\x92\x38" => '\u1d128',
361
            "\xE1\xB4\x92\x39" => '\u1d129',
362
            "\xE1\xB4\x92\x61" => '\u1d12a',
363
            "\xE1\xB4\x92\x62" => '\u1d12b',
364
            "\xE1\xB4\x92\x63" => '\u1d12c',
365
            "\xE1\xB4\x92\x64" => '\u1d12d',
366
            "\xE1\xB4\x92\x65" => '\u1d12e',
367
            "\xE1\xB4\x92\x66" => '\u1d12f',
368
            "\xE1\xB4\x93\x30" => '\u1d130',
369
            "\xE1\xB4\x93\x31" => '\u1d131',
370
            "\xE1\xB4\x93\x32" => '\u1d132',
371
            "\xE1\xB4\x93\x33" => '\u1d133',
372
            "\xE1\xB4\x93\x34" => '\u1d134',
373
            "\xE1\xB4\x93\x35" => '\u1d135',
374
            "\xE1\xB4\x93\x36" => '\u1d136',
375
            "\xE1\xB4\x93\x37" => '\u1d137',
376
            "\xE1\xB4\x93\x38" => '\u1d138',
377
            "\xE1\xB4\x93\x39" => '\u1d139',
378
            "\xE1\xB4\x93\x61" => '\u1d13a',
379
            "\xE1\xB4\x93\x62" => '\u1d13b',
380
            "\xE1\xB4\x93\x63" => '\u1d13c',
381
            "\xE1\xB4\x93\x64" => '\u1d13d',
382
            "\xE1\xB4\x93\x65" => '\u1d13e',
383
            "\xE1\xB4\x93\x66" => '\u1d13f',
384
            "\xE1\xB4\x94\x30" => '\u1d140',
385
            "\xE1\xB4\x94\x31" => '\u1d141',
386
            "\xE1\xB4\x94\x32" => '\u1d142',
387
            "\xE1\xB4\x94\x33" => '\u1d143',
388
            "\xE1\xB4\x94\x34" => '\u1d144',
389
            "\xE1\xB4\x94\x35" => '\u1d145',
390
            "\xE1\xB4\x94\x36" => '\u1d146',
391
            "\xE1\xB4\x94\x37" => '\u1d147',
392
            "\xE1\xB4\x94\x38" => '\u1d148',
393
            "\xE1\xB4\x94\x39" => '\u1d149',
394
            "\xE1\xB4\x94\x61" => '\u1d14a',
395
            "\xE1\xB4\x94\x62" => '\u1d14b',
396
            "\xE1\xB4\x94\x63" => '\u1d14c',
397
            "\xE1\xB4\x94\x64" => '\u1d14d',
398
            "\xE1\xB4\x94\x65" => '\u1d14e',
399
            "\xE1\xB4\x94\x66" => '\u1d14f',
400
            "\xE1\xB4\x95\x30" => '\u1d150',
401
            "\xE1\xB4\x95\x31" => '\u1d151',
402
            "\xE1\xB4\x95\x32" => '\u1d152',
403
            "\xE1\xB4\x95\x33" => '\u1d153',
404
            "\xE1\xB4\x95\x34" => '\u1d154',
405
            "\xE1\xB4\x95\x35" => '\u1d155',
406
            "\xE1\xB4\x95\x36" => '\u1d156',
407
            "\xE1\xB4\x95\x37" => '\u1d157',
408
            "\xE1\xB4\x95\x38" => '\u1d158',
409
            "\xE1\xB4\x95\x39" => '\u1d159',
410
            "\xE1\xB4\x95\x61" => '\u1d15a',
411
            "\xE1\xB4\x95\x62" => '\u1d15b',
412
            "\xE1\xB4\x95\x63" => '\u1d15c',
413
            "\xE1\xB4\x95\x64" => '\u1d15d',
414
            "\xE1\xB4\x95\x65" => '\u1d15e',
415
            "\xE1\xB4\x95\x66" => '\u1d15f',
416
            "\xE1\xB4\x96\x30" => '\u1d160',
417
            "\xE1\xB4\x96\x31" => '\u1d161',
418
            "\xE1\xB4\x96\x32" => '\u1d162',
419
            "\xE1\xB4\x96\x33" => '\u1d163',
420
            "\xE1\xB4\x96\x34" => '\u1d164',
421
            "\xE1\xB4\x96\x35" => '\u1d165',
422
            "\xE1\xB4\x96\x36" => '\u1d166',
423
            "\xE1\xB4\x96\x37" => '\u1d167',
424
            "\xE1\xB4\x96\x38" => '\u1d168',
425
            "\xE1\xB4\x96\x39" => '\u1d169',
426
            "\xE1\xB4\x96\x61" => '\u1d16a',
427
            "\xE1\xB4\x96\x62" => '\u1d16b',
428
            "\xE1\xB4\x96\x63" => '\u1d16c',
429
            "\xE1\xB4\x96\x64" => '\u1d16d',
430
            "\xE1\xB4\x96\x65" => '\u1d16e',
431
            "\xE1\xB4\x96\x66" => '\u1d16f',
432
            "\xE1\xB4\x97\x30" => '\u1d170',
433
            "\xE1\xB4\x97\x31" => '\u1d171',
434
            "\xE1\xB4\x97\x32" => '\u1d172',
435
            "\xE1\xB4\x97\x33" => '\u1d173',
436
            "\xE1\xB4\x97\x34" => '\u1d174',
437
            "\xE1\xB4\x97\x35" => '\u1d175',
438
            "\xE1\xB4\x97\x36" => '\u1d176',
439
            "\xE1\xB4\x97\x37" => '\u1d177',
440
            "\xE1\xB4\x97\x38" => '\u1d178',
441
            "\xE1\xB4\x97\x39" => '\u1d179',
442
            "\xE1\xB4\x97\x61" => '\u1d17a',
443
            "\xE1\xB4\x97\x62" => '\u1d17b',
444
            "\xE1\xB4\x97\x63" => '\u1d17c',
445
            "\xE1\xB4\x97\x64" => '\u1d17d',
446
            "\xE1\xB4\x97\x65" => '\u1d17e',
447
            "\xE1\xB4\x97\x66" => '\u1d17f',
448
            "\xE1\xB4\x98\x30" => '\u1d180',
449
            "\xE1\xB4\x98\x31" => '\u1d181',
450
            "\xE1\xB4\x98\x32" => '\u1d182',
451
            "\xE1\xB4\x98\x33" => '\u1d183',
452
            "\xE1\xB4\x98\x34" => '\u1d184',
453
            "\xE1\xB4\x98\x35" => '\u1d185',
454
            "\xE1\xB4\x98\x36" => '\u1d186',
455
            "\xE1\xB4\x98\x37" => '\u1d187',
456
            "\xE1\xB4\x98\x38" => '\u1d188',
457
            "\xE1\xB4\x98\x39" => '\u1d189',
458
            "\xE1\xB4\x98\x61" => '\u1d18a',
459
            "\xE1\xB4\x98\x62" => '\u1d18b',
460
            "\xE1\xB4\x98\x63" => '\u1d18c',
461
            "\xE1\xB4\x98\x64" => '\u1d18d',
462
            "\xE1\xB4\x98\x65" => '\u1d18e',
463
            "\xE1\xB4\x98\x66" => '\u1d18f',
464
            "\xE1\xB4\x99\x30" => '\u1d190',
465
            "\xE1\xB4\x99\x31" => '\u1d191',
466
            "\xE1\xB4\x99\x32" => '\u1d192',
467
            "\xE1\xB4\x99\x33" => '\u1d193',
468
            "\xE1\xB4\x99\x34" => '\u1d194',
469
            "\xE1\xB4\x99\x35" => '\u1d195',
470
            "\xE1\xB4\x99\x36" => '\u1d196',
471
            "\xE1\xB4\x99\x37" => '\u1d197',
472
            "\xE1\xB4\x99\x38" => '\u1d198',
473
            "\xE1\xB4\x99\x39" => '\u1d199',
474
            "\xE1\xB4\x99\x61" => '\u1d19a',
475
            "\xE1\xB4\x99\x62" => '\u1d19b',
476
            "\xE1\xB4\x99\x63" => '\u1d19c',
477
            "\xE1\xB4\x99\x64" => '\u1d19d',
478
            "\xE1\xB4\x99\x65" => '\u1d19e',
479
            "\xE1\xB4\x99\x66" => '\u1d19f',
480
            "\xE1\xB4\x9A\x30" => '\u1d1a0',
481
            "\xE1\xB4\x9A\x31" => '\u1d1a1',
482
            "\xE1\xB4\x9A\x32" => '\u1d1a2',
483
            "\xE1\xB4\x9A\x33" => '\u1d1a3',
484
            "\xE1\xB4\x9A\x34" => '\u1d1a4',
485
            "\xE1\xB4\x9A\x35" => '\u1d1a5',
486
            "\xE1\xB4\x9A\x36" => '\u1d1a6',
487
            "\xE1\xB4\x9A\x37" => '\u1d1a7',
488
            "\xE1\xB4\x9A\x38" => '\u1d1a8',
489
            "\xE1\xB4\x9A\x39" => '\u1d1a9',
490
            "\xE1\xB4\x9A\x61" => '\u1d1aa',
491
            "\xE1\xB4\x9A\x62" => '\u1d1ab',
492
            "\xE1\xB4\x9A\x63" => '\u1d1ac',
493
            "\xE1\xB4\x9A\x64" => '\u1d1ad',
494
            "\xE1\xB4\x9A\x65" => '\u1d1ae',
495
            "\xE1\xB4\x9A\x66" => '\u1d1af',
496
            "\xE1\xB4\x9B\x30" => '\u1d1b0',
497
            "\xE1\xB4\x9B\x31" => '\u1d1b1',
498
            "\xE1\xB4\x9B\x32" => '\u1d1b2',
499
            "\xE1\xB4\x9B\x33" => '\u1d1b3',
500
            "\xE1\xB4\x9B\x34" => '\u1d1b4',
501
            "\xE1\xB4\x9B\x35" => '\u1d1b5',
502
            "\xE1\xB4\x9B\x36" => '\u1d1b6',
503
            "\xE1\xB4\x9B\x37" => '\u1d1b7',
504
            "\xE1\xB4\x9B\x38" => '\u1d1b8',
505
            "\xE1\xB4\x9B\x39" => '\u1d1b9',
506
            "\xE1\xB4\x9B\x61" => '\u1d1ba',
507
            "\xE1\xB4\x9B\x62" => '\u1d1bb',
508
            "\xE1\xB4\x9B\x63" => '\u1d1bc',
509
            "\xE1\xB4\x9B\x64" => '\u1d1bd',
510
            "\xE1\xB4\x9B\x65" => '\u1d1be',
511
            "\xE1\xB4\x9B\x66" => '\u1d1bf',
512
            "\xE1\xB4\x9C\x30" => '\u1d1c0',
513
            "\xE1\xB4\x9C\x31" => '\u1d1c1',
514
            "\xE1\xB4\x9C\x32" => '\u1d1c2',
515
            "\xE1\xB4\x9C\x33" => '\u1d1c3',
516
            "\xE1\xB4\x9C\x34" => '\u1d1c4',
517
            "\xE1\xB4\x9C\x35" => '\u1d1c5',
518
            "\xE1\xB4\x9C\x36" => '\u1d1c6',
519
            "\xE1\xB4\x9C\x37" => '\u1d1c7',
520
            "\xE1\xB4\x9C\x38" => '\u1d1c8',
521
            "\xE1\xB4\x9C\x39" => '\u1d1c9',
522
            "\xE1\xB4\x9C\x61" => '\u1d1ca',
523
            "\xE1\xB4\x9C\x62" => '\u1d1cb',
524
            "\xE1\xB4\x9C\x63" => '\u1d1cc',
525
            "\xE1\xB4\x9C\x64" => '\u1d1cd',
526
            "\xE1\xB4\x9C\x65" => '\u1d1ce',
527
            "\xE1\xB4\x9C\x66" => '\u1d1cf',
528
            "\xE1\xB4\x9D\x30" => '\u1d1d0',
529
            "\xE1\xB4\x9D\x31" => '\u1d1d1',
530
            "\xE1\xB4\x9D\x32" => '\u1d1d2',
531
            "\xE1\xB4\x9D\x33" => '\u1d1d3',
532
            "\xE1\xB4\x9D\x34" => '\u1d1d4',
533
            "\xE1\xB4\x9D\x35" => '\u1d1d5',
534
            "\xE1\xB4\x9D\x36" => '\u1d1d6',
535
            "\xE1\xB4\x9D\x37" => '\u1d1d7',
536
            "\xE1\xB4\x9D\x38" => '\u1d1d8',
537
            "\xE1\xB4\x9D\x39" => '\u1d1d9',
538
            "\xE1\xB4\x9D\x61" => '\u1d1da',
539
            "\xE1\xB4\x9D\x62" => '\u1d1db',
540
            "\xE1\xB4\x9D\x63" => '\u1d1dc',
541
            "\xE1\xB4\x9D\x64" => '\u1d1dd',
542
            "\xE1\xB4\x9D\x65" => '\u1d1de',
543
            "\xE1\xB4\x9D\x66" => '\u1d1df',
544
            "\xE1\xB4\x9E\x30" => '\u1d1e0',
545
            "\xE1\xB4\x9E\x31" => '\u1d1e1',
546
            "\xE1\xB4\x9E\x32" => '\u1d1e2',
547
            "\xE1\xB4\x9E\x33" => '\u1d1e3',
548
            "\xE1\xB4\x9E\x34" => '\u1d1e4',
549
            "\xE1\xB4\x9E\x35" => '\u1d1e5',
550
            "\xE1\xB4\x9E\x36" => '\u1d1e6',
551
            "\xE1\xB4\x9E\x37" => '\u1d1e7',
552
            "\xE1\xB4\x9E\x38" => '\u1d1e8',
553
            "\xE1\xB4\x9E\x39" => '\u1d1e9',
554
            "\xE1\xB4\x9E\x61" => '\u1d1ea',
555
            "\xE1\xB4\x9E\x62" => '\u1d1eb',
556
            "\xE1\xB4\x9E\x63" => '\u1d1ec',
557
            "\xE1\xB4\x9E\x64" => '\u1d1ed',
558
            "\xE1\xB4\x9E\x65" => '\u1d1ee',
559
            "\xE1\xB4\x9E\x66" => '\u1d1ef',
560
            "\xE1\xB4\x9F\x30" => '\u1d1f0',
561
            "\xE1\xB4\x9F\x31" => '\u1d1f1',
562
            "\xE1\xB4\x9F\x32" => '\u1d1f2',
563
            "\xE1\xB4\x9F\x33" => '\u1d1f3',
564
            "\xE1\xB4\x9F\x34" => '\u1d1f4',
565
            "\xE1\xB4\x9F\x35" => '\u1d1f5',
566
            "\xE1\xB4\x9F\x36" => '\u1d1f6',
567
            "\xE1\xB4\x9F\x37" => '\u1d1f7',
568
            "\xE1\xB4\x9F\x38" => '\u1d1f8',
569
            "\xE1\xB4\x9F\x39" => '\u1d1f9',
570
            "\xE1\xB4\x9F\x61" => '\u1d1fa',
571
            "\xE1\xB4\x9F\x62" => '\u1d1fb',
572
            "\xE1\xB4\x9F\x63" => '\u1d1fc',
573
            "\xE1\xB4\x9F\x64" => '\u1d1fd',
574
            "\xE1\xB4\x9F\x65" => '\u1d1fe',
575
            "\xE1\xB4\x9F\x66" => '\u1d1ff',
576
577
            // \p{block=Ancient_Greek_Musical_Notation}
578
            "\xE1\xB4\xA0\x30" => '\u1d200',
579
            "\xE1\xB4\xA0\x31" => '\u1d201',
580
            "\xE1\xB4\xA0\x32" => '\u1d202',
581
            "\xE1\xB4\xA0\x33" => '\u1d203',
582
            "\xE1\xB4\xA0\x34" => '\u1d204',
583
            "\xE1\xB4\xA0\x35" => '\u1d205',
584
            "\xE1\xB4\xA0\x36" => '\u1d206',
585
            "\xE1\xB4\xA0\x37" => '\u1d207',
586
            "\xE1\xB4\xA0\x38" => '\u1d208',
587
            "\xE1\xB4\xA0\x39" => '\u1d209',
588
            "\xE1\xB4\xA0\x61" => '\u1d20a',
589
            "\xE1\xB4\xA0\x62" => '\u1d20b',
590
            "\xE1\xB4\xA0\x63" => '\u1d20c',
591
            "\xE1\xB4\xA0\x64" => '\u1d20d',
592
            "\xE1\xB4\xA0\x65" => '\u1d20e',
593
            "\xE1\xB4\xA0\x66" => '\u1d20f',
594
            "\xE1\xB4\xA1\x30" => '\u1d210',
595
            "\xE1\xB4\xA1\x31" => '\u1d211',
596
            "\xE1\xB4\xA1\x32" => '\u1d212',
597
            "\xE1\xB4\xA1\x33" => '\u1d213',
598
            "\xE1\xB4\xA1\x34" => '\u1d214',
599
            "\xE1\xB4\xA1\x35" => '\u1d215',
600
            "\xE1\xB4\xA1\x36" => '\u1d216',
601
            "\xE1\xB4\xA1\x37" => '\u1d217',
602
            "\xE1\xB4\xA1\x38" => '\u1d218',
603
            "\xE1\xB4\xA1\x39" => '\u1d219',
604
            "\xE1\xB4\xA1\x61" => '\u1d21a',
605
            "\xE1\xB4\xA1\x62" => '\u1d21b',
606
            "\xE1\xB4\xA1\x63" => '\u1d21c',
607
            "\xE1\xB4\xA1\x64" => '\u1d21d',
608
            "\xE1\xB4\xA1\x65" => '\u1d21e',
609
            "\xE1\xB4\xA1\x66" => '\u1d21f',
610
            "\xE1\xB4\xA2\x30" => '\u1d220',
611
            "\xE1\xB4\xA2\x31" => '\u1d221',
612
            "\xE1\xB4\xA2\x32" => '\u1d222',
613
            "\xE1\xB4\xA2\x33" => '\u1d223',
614
            "\xE1\xB4\xA2\x34" => '\u1d224',
615
            "\xE1\xB4\xA2\x35" => '\u1d225',
616
            "\xE1\xB4\xA2\x36" => '\u1d226',
617
            "\xE1\xB4\xA2\x37" => '\u1d227',
618
            "\xE1\xB4\xA2\x38" => '\u1d228',
619
            "\xE1\xB4\xA2\x39" => '\u1d229',
620
            "\xE1\xB4\xA2\x61" => '\u1d22a',
621
            "\xE1\xB4\xA2\x62" => '\u1d22b',
622
            "\xE1\xB4\xA2\x63" => '\u1d22c',
623
            "\xE1\xB4\xA2\x64" => '\u1d22d',
624
            "\xE1\xB4\xA2\x65" => '\u1d22e',
625
            "\xE1\xB4\xA2\x66" => '\u1d22f',
626
            "\xE1\xB4\xA3\x30" => '\u1d230',
627
            "\xE1\xB4\xA3\x31" => '\u1d231',
628
            "\xE1\xB4\xA3\x32" => '\u1d232',
629
            "\xE1\xB4\xA3\x33" => '\u1d233',
630
            "\xE1\xB4\xA3\x34" => '\u1d234',
631
            "\xE1\xB4\xA3\x35" => '\u1d235',
632
            "\xE1\xB4\xA3\x36" => '\u1d236',
633
            "\xE1\xB4\xA3\x37" => '\u1d237',
634
            "\xE1\xB4\xA3\x38" => '\u1d238',
635
            "\xE1\xB4\xA3\x39" => '\u1d239',
636
            "\xE1\xB4\xA3\x61" => '\u1d23a',
637
            "\xE1\xB4\xA3\x62" => '\u1d23b',
638
            "\xE1\xB4\xA3\x63" => '\u1d23c',
639
            "\xE1\xB4\xA3\x64" => '\u1d23d',
640
            "\xE1\xB4\xA3\x65" => '\u1d23e',
641
            "\xE1\xB4\xA3\x66" => '\u1d23f',
642
            "\xE1\xB4\xA4\x30" => '\u1d240',
643
            "\xE1\xB4\xA4\x31" => '\u1d241',
644
            "\xE1\xB4\xA4\x32" => '\u1d242',
645
            "\xE1\xB4\xA4\x33" => '\u1d243',
646
            "\xE1\xB4\xA4\x34" => '\u1d244',
647
            "\xE1\xB4\xA4\x35" => '\u1d245',
648
            "\xE1\xB4\xA4\x36" => '\u1d246',
649
            "\xE1\xB4\xA4\x37" => '\u1d247',
650
            "\xE1\xB4\xA4\x38" => '\u1d248',
651
            "\xE1\xB4\xA4\x39" => '\u1d249',
652
            "\xE1\xB4\xA4\x61" => '\u1d24a',
653
            "\xE1\xB4\xA4\x62" => '\u1d24b',
654
            "\xE1\xB4\xA4\x63" => '\u1d24c',
655
            "\xE1\xB4\xA4\x64" => '\u1d24d',
656
            "\xE1\xB4\xA4\x65" => '\u1d24e',
657
            "\xE1\xB4\xA4\x66" => '\u1d24f',
658
659
        );
660
661 20
        $sanitized = '';
662 20
        $pointer = 0;
663 20
        while (($char = self::unicodeNextChar($data, $pointer)) !== false) {
664 20
            if (isset($excluded[$char])) {
665 2
                return 'Invalid character: ' . $excluded[$char];
666
            }
667 19
            $sanitized .= strlen($char) === 1 ? $char : 'a';
668
        }
669
670 18
        return null;
671
    }
672
673
    /**
674
     * @see https://stackoverflow.com/a/14366023/329463
675
     * @param string $string
676
     * @param int $pointer
677
     * @return false|string
678
     */
679 20
    private static function unicodeNextChar($string, &$pointer)
680
    {
681 20
        if (!isset($string[$pointer])) return false;
682 20
        $char = ord($string[$pointer]);
683 20
        if ($char < 128) {
684 16
            return $string[$pointer++];
685
        } else {
686 16
            if ($char < 224) {
687 12
                $bytes = 2;
688 7
            } elseif ($char < 240) {
689 7
                $bytes = 3;
690
            } elseif ($char < 248) {
691
                $bytes = 4;
692
            } elseif ($char == 252) {
693
                $bytes = 5;
694
            } else {
695
                $bytes = 6;
696
            }
697 16
            $str = substr($string, $pointer, $bytes);
698 16
            $pointer += $bytes;
699 16
            return $str;
700
        }
701
    }
702
703
}