1
|
|
|
<?php |
2
|
|
|
declare(strict_types = 1); |
3
|
|
|
namespace hexydec\agentzero; |
4
|
|
|
|
5
|
|
|
class devices { |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Generates a configuration array for matching devices |
9
|
|
|
* |
10
|
|
|
* @return array<string,props> An array with keys representing the string to match, and values a props object defining how to generate the match and which properties to set |
11
|
|
|
*/ |
12
|
91 |
|
public static function get() : array { |
13
|
3 |
|
$fn = [ |
14
|
3 |
|
'ios' => function (string $value, int $i, array $tokens) : array { |
15
|
19 |
|
$version = null; |
16
|
19 |
|
$model = null; |
17
|
|
|
|
18
|
|
|
// device name with slash like iPhone/16.5 |
19
|
19 |
|
$parts = \explode('/', $value, 3); |
20
|
19 |
|
if (isset($parts[1])) { |
21
|
1 |
|
$value = $parts[0]; |
22
|
1 |
|
$version = $parts[1]; |
23
|
|
|
} |
24
|
|
|
|
25
|
|
|
// look at other tokens to gather info |
26
|
19 |
|
foreach ($tokens AS $item) { |
27
|
19 |
|
if (\str_starts_with($item, 'Mobile/')) { |
28
|
19 |
|
$model = \mb_substr($item, 7); |
29
|
19 |
|
} elseif (\str_starts_with($item, 'CPU iPhone OS ')) { |
30
|
18 |
|
$version = \str_replace('_', '.', \mb_substr($item, 14, \mb_strpos($item, ' ', 14) - 14)); |
31
|
19 |
|
} elseif (\str_starts_with($item, 'CPU OS ')) { |
32
|
2 |
|
$version = \str_replace('_', '.', \mb_substr($item, 7, \mb_strpos($item, ' ', 7) - 7)); |
33
|
|
|
} |
34
|
|
|
} |
35
|
19 |
|
return [ |
36
|
19 |
|
'type' => 'human', |
37
|
19 |
|
'category' => $value === 'iPad' ? 'tablet' : 'mobile', |
38
|
19 |
|
'architecture' => 'Arm', |
39
|
19 |
|
'bits' => $value === 'iPod' ? 32 : 64, |
40
|
19 |
|
'kernel' => 'Linux', |
41
|
19 |
|
'platform' => 'iOS', |
42
|
19 |
|
'platformversion' => $version, |
43
|
19 |
|
'vendor' => 'Apple', |
44
|
19 |
|
'device' => \mb_stripos($value, 'iPhone') === 0 ? 'iPhone' : $value, |
45
|
19 |
|
'model' => $model |
46
|
19 |
|
]; |
47
|
3 |
|
}, |
48
|
3 |
|
'xbox' => fn (string $value) : array => [ |
49
|
3 |
|
'type' => 'human', |
50
|
3 |
|
'category' => 'console', |
51
|
3 |
|
'vendor' => 'Microsoft', |
52
|
3 |
|
'device' => 'Xbox', |
53
|
3 |
|
'model' => ($model = \mb_substr($value, 5)) === '' ? null : $model |
54
|
3 |
|
], |
55
|
3 |
|
'playstation' => function (string $value) : array { |
56
|
1 |
|
$parts = \explode(' ', $value); |
57
|
1 |
|
if (\str_contains($parts[1], '/')) { |
58
|
1 |
|
list($parts[1], $parts[2]) = \explode('/', $parts[1]); |
59
|
|
|
} |
60
|
1 |
|
$platform = [ |
61
|
1 |
|
'4' => 'Orbis OS', |
62
|
1 |
|
'5' => 'FreeBSD' |
63
|
1 |
|
]; |
64
|
1 |
|
return [ |
65
|
1 |
|
'device' => 'PlayStation', |
66
|
1 |
|
'model' => $parts[1] ?? null, |
67
|
1 |
|
'kernel' => 'Linux', |
68
|
1 |
|
'platform' => $platform[$parts[1]] ?? null, |
69
|
1 |
|
'platformversion' => $parts[2] ?? null, |
70
|
1 |
|
'type' => 'human', |
71
|
1 |
|
'category' => 'console', |
72
|
1 |
|
'vendor' => 'Sony', |
73
|
1 |
|
'processor' => 'AMD', |
74
|
1 |
|
'architecture' => 'x86', |
75
|
1 |
|
'bits' => 64 |
76
|
1 |
|
]; |
77
|
3 |
|
}, |
78
|
3 |
|
'firetablet' => function (string $value) : ?array { |
79
|
3 |
|
$model = \explode(' ', $value)[0]; |
80
|
3 |
|
if (\ctype_alpha($model) && \mb_strlen($model) <= 7) { |
81
|
3 |
|
return [ |
82
|
3 |
|
'type' => 'human', |
83
|
3 |
|
'category' => 'tablet', |
84
|
3 |
|
'vendor' => 'Amazon', |
85
|
3 |
|
'device' => 'Fire Tablet', |
86
|
3 |
|
'model' => $model |
87
|
3 |
|
]; |
88
|
|
|
} |
89
|
|
|
return null; |
90
|
3 |
|
} |
91
|
3 |
|
]; |
92
|
34 |
|
return [ |
93
|
34 |
|
'iPhone' => new props('start', $fn['ios']), |
94
|
34 |
|
'iPad' => new props('exact', $fn['ios']), |
95
|
34 |
|
'iPod' => new props('exact', $fn['ios']), |
96
|
34 |
|
'iPod touch' => new props('exact', $fn['ios']), |
97
|
34 |
|
'Macintosh' => new props('exact', [ |
98
|
34 |
|
'vendor' => 'Apple', |
99
|
34 |
|
'device' => 'Macintosh' |
100
|
34 |
|
]), |
101
|
34 |
|
'Quest' => new props('start', fn (string $value) : array => [ |
102
|
4 |
|
'vendor' => 'Oculus', |
103
|
4 |
|
'device' => 'Quest', |
104
|
4 |
|
'model' => ($model = \mb_substr($value, 6)) === '' ? null : $model, |
105
|
4 |
|
'type' => 'human', |
106
|
4 |
|
'category' => 'vr' |
107
|
4 |
|
]), |
108
|
34 |
|
'Pacific' => new props('start', [ |
109
|
34 |
|
'vendor' => 'Oculus', |
110
|
34 |
|
'device' => 'Go', |
111
|
34 |
|
'type' => 'human', |
112
|
34 |
|
'category' => 'vr' |
113
|
34 |
|
]), |
114
|
34 |
|
'Nintendo' => new props('start', fn (string $value) : array => [ |
115
|
4 |
|
'type' => 'human', |
116
|
4 |
|
'category' => 'console', |
117
|
4 |
|
'vendor' => 'Nintendo', |
118
|
4 |
|
'device' => $value === 'Nintendo WiiU' ? 'Wii U' : \mb_substr($value, 9), |
119
|
4 |
|
'architecture' => \str_ends_with($value, 'U') ? 'PowerPC' : null |
120
|
4 |
|
]), |
121
|
34 |
|
'Xbox Series S' => new props('exact', $fn['xbox']), |
122
|
34 |
|
'Xbox Series X' => new props('exact', $fn['xbox']), |
123
|
34 |
|
'Xbox One' => new props('exact', $fn['xbox']), |
124
|
34 |
|
'Xbox 360' => new props('exact', $fn['xbox']), |
125
|
34 |
|
'Xbox' => new props('exact', $fn['xbox']), |
126
|
34 |
|
'Playstation 3' => new props('start', $fn['playstation']), |
127
|
34 |
|
'Playstation 4' => new props('start', $fn['playstation']), |
128
|
34 |
|
'Playstation 5' => new props('start', $fn['playstation']), |
129
|
34 |
|
'Playstation Vita' => new props('start', fn (string $value) : array => [ |
130
|
2 |
|
'type' => 'human', |
131
|
2 |
|
'category' => 'console', |
132
|
2 |
|
'vendor' => 'Sony', |
133
|
2 |
|
'device' => 'PlayStation', |
134
|
2 |
|
'model' => 'Vita', |
135
|
2 |
|
'architecture' => 'Arm', |
136
|
2 |
|
'processor' => 'MediaTek', |
137
|
2 |
|
'cpu' => 'Cortex-A9 MPCore', |
138
|
2 |
|
'bits' => 32, |
139
|
2 |
|
'width' => 960, |
140
|
2 |
|
'height' => 544, |
141
|
2 |
|
'dpi' => 220, |
142
|
2 |
|
'ram' => 512, |
143
|
2 |
|
'kernel' => 'Linux', |
144
|
2 |
|
'platform' => 'PlayStation Vita System Software', |
145
|
2 |
|
'platformversion' => \mb_substr($value, 17) |
146
|
2 |
|
]), |
147
|
34 |
|
'Playstation Portable' => new props('start', fn (string $value, int $i, array $tokens) : array => [ |
148
|
2 |
|
'type' => 'human', |
149
|
2 |
|
'category' => 'console', |
150
|
2 |
|
'vendor' => 'Sony', |
151
|
2 |
|
'device' => 'PlayStation', |
152
|
2 |
|
'model' => 'PSP', |
153
|
2 |
|
'architecture' => 'Arm', |
154
|
2 |
|
'cpu' => 'MIPS R4000', |
155
|
2 |
|
'cpuclock' => 333, |
156
|
2 |
|
'bits' => 64, |
157
|
2 |
|
'width' => 480, |
158
|
2 |
|
'height' => 272, |
159
|
2 |
|
'ram' => 64, |
160
|
2 |
|
'kernel' => 'Linux', |
161
|
2 |
|
'platform' => 'PlayStation Portable System Software', |
162
|
2 |
|
'platformversion' => $tokens[++$i], |
163
|
2 |
|
'browser' => 'NetFront', |
164
|
2 |
|
'engine' => 'WebKit' |
165
|
2 |
|
]), |
166
|
34 |
|
'SHIELD Android TV' => new props('start', [ |
167
|
34 |
|
'type' => 'human', |
168
|
34 |
|
'category' => 'console', |
169
|
34 |
|
'vendor' => 'NVIDIA', |
170
|
34 |
|
'device' => 'Shield' |
171
|
34 |
|
]), |
172
|
34 |
|
'CrKey/' => new props('start', fn (string $value) : array => [ |
173
|
3 |
|
'type' => 'human', |
174
|
3 |
|
'category' => 'tv', |
175
|
3 |
|
'app' => 'Chromecast', |
176
|
3 |
|
'appname' => 'CrKey', |
177
|
3 |
|
'appversion' => \explode(',', \mb_substr($value, 6), 2)[0] |
178
|
3 |
|
]), |
179
|
34 |
|
'ChromeBook' => new props('any', [ |
180
|
34 |
|
'type' => 'human', |
181
|
34 |
|
'category' => 'desktop' |
182
|
34 |
|
]), |
183
|
34 |
|
'GoogleTV' => new props('exact', [ |
184
|
34 |
|
'type' => 'human', |
185
|
34 |
|
'category' => 'tv', |
186
|
34 |
|
'device' => 'GoogleTV' |
187
|
34 |
|
]), |
188
|
34 |
|
'CriKey/' => new props('start', fn (string $value) : array => [ |
189
|
1 |
|
'type' => 'human', |
190
|
1 |
|
'category' => 'tv', |
191
|
1 |
|
'device' => 'Chromecast', |
192
|
1 |
|
'vendor' => 'Google', |
193
|
1 |
|
'platformversion' => \mb_substr($value, 7) |
194
|
1 |
|
]), |
195
|
34 |
|
'Apple/' => new props('start', function (string $value) : array { |
196
|
1 |
|
$value = \mb_substr($value, 6); |
197
|
1 |
|
$split = \strcspn($value, '0123456789'); |
198
|
1 |
|
$device = \mb_substr($value, 0, $split); |
199
|
1 |
|
return [ |
200
|
1 |
|
'type' => 'human', |
201
|
1 |
|
'category' => $device === 'iPad' ? 'tablet' : 'mobile', |
202
|
1 |
|
'vendor' => 'Apple', |
203
|
1 |
|
'device' => $device, |
204
|
1 |
|
'model' => \mb_substr($value, $split) ?: null |
205
|
1 |
|
]; |
206
|
34 |
|
}), |
207
|
34 |
|
'hw/iPhone' => new props('start', fn (string $value) : array => [ |
208
|
1 |
|
'platform' => 'iOS', |
209
|
1 |
|
'vendor' => 'Apple', |
210
|
1 |
|
'device' => 'iPhone', |
211
|
1 |
|
'model' => \str_replace('_', '.', \mb_substr($value, 9)) |
212
|
1 |
|
]), |
213
|
34 |
|
'KF' => new props('start', $fn['firetablet']), |
214
|
34 |
|
'AFT' => new props('start', fn (string $value) : array => [ |
215
|
2 |
|
'type' => 'human', |
216
|
2 |
|
'category' => 'tv', |
217
|
2 |
|
'vendor' => 'Amazon', |
218
|
2 |
|
'device' => 'Fire TV', |
219
|
2 |
|
'model' => $value |
220
|
2 |
|
]), |
221
|
34 |
|
'Roku/' => new props('start', fn (string $value, int $i, array $tokens) : array => [ |
222
|
2 |
|
'type' => 'human', |
223
|
2 |
|
'category' => 'tv', |
224
|
2 |
|
'kernel' => 'Linux', |
225
|
2 |
|
'platform' => 'Roku OS', |
226
|
2 |
|
'platformversion' => $tokens[++$i] ?? null, |
227
|
2 |
|
'vendor' => 'Roku', |
228
|
2 |
|
'device' => \mb_substr($value, 5) |
229
|
2 |
|
]), |
230
|
34 |
|
'AmigaOneX' => new props('start', fn (string $value) : array => [ |
231
|
2 |
|
'type' => 'human', |
232
|
2 |
|
'category' => 'desktop', |
233
|
2 |
|
'vendor' => 'A-Eon Technology', |
234
|
2 |
|
'device' => 'AmigaOne', |
235
|
2 |
|
'model' => \mb_substr($value, 8) |
236
|
2 |
|
]), |
237
|
34 |
|
'googleweblight' => new props('exact', [ |
238
|
34 |
|
'proxy' => 'googleweblight' |
239
|
34 |
|
]), |
240
|
34 |
|
'SAMSUNG-' => new props('start', function (string $value) : array { |
241
|
2 |
|
$parts = \explode('/', $value, 2); |
242
|
2 |
|
return [ |
243
|
2 |
|
'type' => 'human', |
244
|
2 |
|
'category' => 'mobile', |
245
|
2 |
|
'vendor' => 'Samsung', |
246
|
2 |
|
'model' => \mb_substr($parts[0], 8), |
247
|
2 |
|
'build' => $parts[1] ?? null, |
248
|
2 |
|
]; |
249
|
34 |
|
}), |
250
|
12 |
|
'Samsung' => new props('start', fn (string $value) : ?array => \str_starts_with($value, 'SamsungBrowser') ? null : [ |
251
|
12 |
|
'vendor' => 'Samsung' |
252
|
12 |
|
]), |
253
|
34 |
|
'SM-' => new props('start', function (string $value) : array { |
254
|
10 |
|
$parts = \explode('.', \explode(' ', $value)[0]); |
255
|
10 |
|
return [ |
256
|
10 |
|
'vendor' => 'Samsung', |
257
|
10 |
|
'model' => $parts[0], |
258
|
10 |
|
'build' => $parts[1] ?? null |
259
|
10 |
|
]; |
260
|
34 |
|
}), |
261
|
34 |
|
'Acer' => new props('start', [ |
262
|
34 |
|
'vendor' => 'Acer' |
263
|
34 |
|
]), |
264
|
34 |
|
'SonyEricsson' => new props('start', function (string $value) : array { |
265
|
1 |
|
$parts = \explode('/', $value, 2); |
266
|
1 |
|
return [ |
267
|
1 |
|
'type' => 'human', |
268
|
1 |
|
'category' => 'mobile', |
269
|
1 |
|
'vendor' => 'Sony Ericsson', |
270
|
1 |
|
'model' => \mb_substr($parts[0], 12), |
271
|
1 |
|
'build' => $parts[1] ?? null |
272
|
1 |
|
]; |
273
|
34 |
|
}), |
274
|
34 |
|
'LGE' => new props('exact', function (string $value, int $i, array $tokens) : array { |
275
|
1 |
|
$device = $tokens[++$i] ?? null; |
276
|
1 |
|
$platformversion = empty($tokens[++$i]) ? null : \mb_substr(\explode(' ', $tokens[$i])[0], 5); |
277
|
1 |
|
$build = $tokens[++$i] ?? null; |
278
|
1 |
|
return [ |
279
|
1 |
|
'type' => 'human', |
280
|
1 |
|
'category' => 'tv', |
281
|
1 |
|
'model' => $device, |
282
|
1 |
|
'build' => $build, |
283
|
1 |
|
'platformversion' => $platformversion, |
284
|
1 |
|
'vendor' => 'LG' |
285
|
1 |
|
]; |
286
|
34 |
|
}), |
287
|
34 |
|
'LG-' => new props('start', function (string $value) : array { |
288
|
1 |
|
$parts = \explode('/', \mb_substr($value, 3), 3); |
289
|
1 |
|
return [ |
290
|
1 |
|
'type' => 'human', |
291
|
1 |
|
'category' => 'mobile', |
292
|
1 |
|
'vendor' => 'LG', |
293
|
1 |
|
'model' => \explode(' ', $parts[0])[0], |
294
|
1 |
|
'build' => $parts[1] ?? null |
295
|
1 |
|
]; |
296
|
34 |
|
}), |
297
|
34 |
|
'NOKIA' => new props('start', fn (string $value) : array => \array_merge(devices::getDevice($value), [ |
298
|
34 |
|
'type' => 'human', |
299
|
34 |
|
'category' => 'mobile', |
300
|
34 |
|
'vendor' => 'Nokia', |
301
|
34 |
|
])), |
302
|
34 |
|
'Lumia' => new props('start', fn (string $value) : array => \array_merge(devices::getDevice($value), [ |
303
|
34 |
|
'type' => 'human', |
304
|
34 |
|
'category' => 'mobile', |
305
|
34 |
|
'vendor' => 'Nokia' |
306
|
34 |
|
])), |
307
|
34 |
|
'BRAVIA' => new props('start', [ |
308
|
34 |
|
'type' => 'human', |
309
|
34 |
|
'category' => 'tv', |
310
|
34 |
|
'vendor' => 'Sony', |
311
|
34 |
|
'device' => 'Bravia' |
312
|
34 |
|
]), |
313
|
34 |
|
'TECNO' => new props('start', fn (string $value) : array => [ |
314
|
3 |
|
'type' => 'human', |
315
|
3 |
|
'category' => 'mobile', |
316
|
3 |
|
'vendor' => 'Tecno', |
317
|
3 |
|
'model' => \explode(' ', \str_replace('-', ' ', $value), 2)[1] ?? null |
318
|
3 |
|
]), |
319
|
34 |
|
'Xiaomi' => new props('start', function (string $value, int $i, array $tokens) : array { |
320
|
5 |
|
return [ |
321
|
5 |
|
'type' => 'human', |
322
|
5 |
|
'vendor' => 'Xiaomi', |
323
|
5 |
|
'device' => \mb_stripos($value, 'Poco') !== false ? 'Poco' : null, |
324
|
5 |
|
'model' => \mb_stripos($value, 'Xiaomi-Mi') !== 0 ? (\explode(' ', $value)[1] ?? null) : null, |
325
|
5 |
|
'platformversion' => \is_numeric($tokens[$i+1] ?? null) ? $tokens[$i+1] : null |
326
|
5 |
|
]; |
327
|
34 |
|
}), |
328
|
34 |
|
'ThinkPad' => new props('start', function (string $value, int $i, array $tokens) : array { |
329
|
1 |
|
if (\mb_strpos($tokens[++$i] ?? '', 'Build/') === 0) { |
330
|
1 |
|
$device = \explode('_', \mb_substr($tokens[$i], 6)); |
331
|
|
|
} |
332
|
1 |
|
return [ |
333
|
1 |
|
'type' => 'human', |
334
|
1 |
|
'vendor' => 'Lenovo', |
335
|
1 |
|
'device' => $device[0] ?? null, |
336
|
1 |
|
'model' => $device[1] ?? null, |
337
|
1 |
|
'build' => $device[2] ?? null |
338
|
1 |
|
]; |
339
|
34 |
|
}), |
340
|
34 |
|
'BlackBerry' => new props('start', function (string $value) : array { |
341
|
1 |
|
$parts = \explode('/', $value); |
342
|
1 |
|
return [ |
343
|
1 |
|
'type' => 'human', |
344
|
1 |
|
'category' => 'mobile', |
345
|
1 |
|
'vendor' => 'Blackberry', |
346
|
1 |
|
'device' => \mb_substr($parts[0], 10) ?: null, |
347
|
1 |
|
'platform' => 'Blackberry OS', |
348
|
1 |
|
'platformversion' => $parts[1] ?? null |
349
|
1 |
|
]; |
350
|
34 |
|
}), |
351
|
34 |
|
'CUBOT' => new props('exact', fn () : array => [ |
352
|
2 |
|
'type' => 'human', |
353
|
2 |
|
'vendor' => 'Cubot' |
354
|
2 |
|
]), |
355
|
34 |
|
'TCL ' => new props('start', fn (string $value) : array => [ |
356
|
2 |
|
'type' => 'human', |
357
|
2 |
|
'category' => 'tv', |
358
|
2 |
|
'vendor' => 'TCL', |
359
|
2 |
|
'model' => \mb_substr($value, 4) |
360
|
2 |
|
]), |
361
|
34 |
|
'deviceName/' => new props('start', fn (string $value) : array => self::getDevice(\mb_substr($value, 11))), |
362
|
34 |
|
'deviceModel/' => new props('start', fn (string $value) : array => [ |
363
|
2 |
|
'model' => \mb_substr($value, 12) |
364
|
2 |
|
]), |
365
|
34 |
|
'Model/' => new props('start', fn (string $value) : array => [ |
366
|
1 |
|
'model' => \mb_substr($value, 6) |
367
|
1 |
|
]), |
368
|
34 |
|
'Build/' => new props('any', fn (string $value) : array => self::getDevice($value)), |
369
|
34 |
|
'width=' => new props('start', fn (string $value) : array => [ |
370
|
2 |
|
'width' => \intval(\mb_substr($value, 6)) |
371
|
2 |
|
]), |
372
|
34 |
|
'height=' => new props('start', fn (string $value) : array => [ |
373
|
2 |
|
'height' => \intval(\mb_substr($value, 7)) |
374
|
2 |
|
]), |
375
|
34 |
|
'dpi=' => new props('start', fn (string $value) : array => [ |
376
|
1 |
|
'dpi' => \mb_substr($value, 4) |
377
|
1 |
|
]), |
378
|
34 |
|
'NetType/' => new props('start', function (string $value) : array { |
379
|
4 |
|
$type = \mb_convert_case(\mb_substr($value, 8), MB_CASE_UPPER); |
380
|
4 |
|
return [ |
381
|
4 |
|
'nettype' => \in_array($type, ['WF', 'WIFI'], true) ? 'WiFi' : $type |
382
|
4 |
|
]; |
383
|
34 |
|
}), |
384
|
34 |
|
'netWorkType/' => new props('start', function (string $value) : array { |
385
|
1 |
|
$type = \mb_convert_case(\mb_substr($value, 12), MB_CASE_UPPER); |
386
|
1 |
|
return [ |
387
|
1 |
|
'nettype' => \in_array($type, ['WF', 'WIFI'], true) ? 'WiFi' : $type |
388
|
1 |
|
]; |
389
|
34 |
|
}), |
390
|
34 |
|
'2G' => new props('exact', ['nettype' => '2g']), |
391
|
34 |
|
'3G' => new props('exact', ['nettype' => '3g']), |
392
|
34 |
|
'4G' => new props('exact', ['nettype' => '4g']), |
393
|
34 |
|
'4.5G' => new props('exact', ['nettype' => '4g']), |
394
|
34 |
|
'4.5G+' => new props('exact', ['nettype' => '4g']), |
395
|
34 |
|
'5G' => new props('exact', ['nettype' => '5g']), |
396
|
34 |
|
'x' => new props('any', function (string $value) : ?array { |
397
|
91 |
|
if (\str_contains($value, '@')) { |
398
|
2 |
|
$dpi = \explode('@', $value); |
399
|
2 |
|
$value = $dpi[0]; |
400
|
|
|
} |
401
|
91 |
|
$parts = \explode('x', $value); |
402
|
91 |
|
if (!isset($parts[2]) && \is_numeric($parts[0]) && \is_numeric($parts[1]) && !empty($parts[0]) && !empty($parts[1])) { |
403
|
11 |
|
return [ |
404
|
11 |
|
'width' => \intval($parts[0]), |
405
|
11 |
|
'height' => \intval($parts[1]), |
406
|
11 |
|
'density' => isset($dpi[1]) ? \floatval(\rtrim($dpi[1], 'x')) : null |
407
|
11 |
|
]; |
408
|
|
|
} |
409
|
91 |
|
return null; |
410
|
34 |
|
}), |
411
|
34 |
|
'MB' => new props('end', fn (string $value) : array => [ |
412
|
2 |
|
'ram' => \intval(\mb_substr($value, 0, -2)) |
413
|
2 |
|
]) |
414
|
34 |
|
]; |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
/** |
418
|
|
|
* Extracts device information from a token |
419
|
|
|
* |
420
|
|
|
* @param string $value A token expected to contain device information |
421
|
|
|
* @return array<string,string|null> An array containing the extracted devices information |
422
|
|
|
*/ |
423
|
43 |
|
public static function getDevice(string $value) : array { |
424
|
43 |
|
foreach (['Mobile', 'Tablet', 'Safari', 'AppleWebKit', 'Linux', 'rv:'] AS $item) { |
425
|
43 |
|
if (\mb_stripos($value, $item) === 0) { |
426
|
8 |
|
return []; |
427
|
|
|
} |
428
|
|
|
} |
429
|
38 |
|
$parts = \explode('Build/', \str_ireplace('build/', 'Build/', $value), 2); |
|
|
|
|
430
|
38 |
|
$parts[0] = \trim($parts[0]); |
431
|
38 |
|
$build = $parts[1] ?? null; |
432
|
38 |
|
$vendors = [ |
433
|
38 |
|
'Samsung' => 'Samsung', |
434
|
38 |
|
'OnePlus' => 'OnePlus', |
435
|
38 |
|
'CPH' =>'OnePlus', |
436
|
38 |
|
'KB' => 'OnePlus', |
437
|
38 |
|
'Pixel' => 'Google', |
438
|
38 |
|
'SM-' => 'Samsung', |
439
|
38 |
|
'LM-' => 'LG', |
440
|
38 |
|
'LG' => 'LG', |
441
|
38 |
|
'LG-' => 'LG', |
442
|
38 |
|
'RealMe' => 'RealMe', |
443
|
38 |
|
'RMX' => 'RealMe', |
444
|
38 |
|
'HTC' => 'HTC', |
445
|
38 |
|
'Nexus' => 'Google', |
446
|
38 |
|
'Redmi' => 'Redmi', // must be above 'MI ' |
447
|
38 |
|
'MI ' => 'Xiaomi', |
448
|
38 |
|
'HM ' => 'Xiaomi', |
449
|
38 |
|
'Xiaomi' => 'Xiaomi', |
450
|
38 |
|
'Huawei' => 'Huawei', |
451
|
38 |
|
'Honor' => 'Honor', |
452
|
38 |
|
'Motorola' => 'Motorola', |
453
|
38 |
|
'moto' => 'Motorola', |
454
|
38 |
|
'Intel' => 'Intel', |
455
|
38 |
|
'SonyEricsson' => 'Sony Ericsson', |
456
|
38 |
|
'Tecno' => 'Tecno', |
457
|
38 |
|
'Vivo' => 'Vivo', |
458
|
38 |
|
'Oppo' => 'Oppo', |
459
|
38 |
|
'Asus' => 'Asus', |
460
|
38 |
|
'Acer' => 'Acer', |
461
|
38 |
|
'Alcatel' => 'Alcatel', |
462
|
38 |
|
'Infinix' => 'Infinix', |
463
|
38 |
|
'Poco' => 'Poco', |
464
|
38 |
|
'Cubot' => 'Cubot', |
465
|
38 |
|
'Kingkong' => 'Cubot', |
466
|
38 |
|
'Nokia' => 'Nokia', |
467
|
38 |
|
'WR' => 'Westinghouse', |
468
|
38 |
|
'HKP' => 'HKPro', |
469
|
38 |
|
'Roku' => 'Roku', |
470
|
38 |
|
'TCL' => 'TCL' |
471
|
38 |
|
]; |
472
|
|
|
|
473
|
|
|
// find vendor |
474
|
38 |
|
$vendor = null; |
475
|
38 |
|
foreach ($vendors AS $key => $item) { |
476
|
38 |
|
if (($pos = \mb_stripos($value, $key)) !== false) { |
477
|
29 |
|
$vendor = self::getVendor($item); |
478
|
|
|
|
479
|
|
|
// remove vendor name |
480
|
29 |
|
if ($pos === 0 && ($key === $item || $key === 'SonyEricsson')) { |
481
|
17 |
|
$parts[0] = \trim(\mb_substr($parts[0], \mb_strlen($key)), ' -_/'); |
482
|
|
|
} |
483
|
29 |
|
break; |
484
|
|
|
} |
485
|
|
|
} |
486
|
38 |
|
$model = \explode(' ', \str_replace('_', ' ', $parts[0]), 2); |
487
|
38 |
|
$device = $model[0] !== '' && \ctype_alpha($model[0]) ? \ucfirst($model[0]) : null; // device name if only letters |
488
|
38 |
|
$model = $device === null ? \implode(' ', $model) : ($model[1] ?? null); // reconstruct remainder of device name |
489
|
|
|
|
490
|
|
|
// remove everything after a slash |
491
|
38 |
|
if ($build === null && \str_contains($model ?? '', '/')) { |
492
|
1 |
|
$model = \mb_strstr($model, '/', true); |
|
|
|
|
493
|
|
|
} |
494
|
|
|
|
495
|
|
|
// special case for SMART TV |
496
|
38 |
|
if (\strcasecmp($device.$model, 'smarttv') === 0) { |
497
|
1 |
|
$device = 'Smart TV'; |
498
|
1 |
|
$model = null; |
499
|
|
|
} |
500
|
|
|
// var_dump($value, $parts, $device, $model); |
501
|
38 |
|
return [ |
502
|
38 |
|
'vendor' => $vendor, |
503
|
38 |
|
'device' => $device, |
504
|
38 |
|
'model' => $model ? \ucwords($model) : null, |
505
|
38 |
|
'build' => $build |
506
|
38 |
|
]; |
507
|
|
|
} |
508
|
|
|
|
509
|
30 |
|
public static function getVendor(string $value) : string { |
510
|
30 |
|
$map = [ |
511
|
30 |
|
'oneplus' => 'OnePlus', |
512
|
30 |
|
'lg' => 'LG', |
513
|
30 |
|
'lge' => 'LG', |
514
|
30 |
|
'realme' => 'RealMe', |
515
|
30 |
|
'htc' => 'HTC', |
516
|
30 |
|
'sonyericsson' => 'Sony Ericsson', |
517
|
30 |
|
'tcl' => 'TCL', |
518
|
30 |
|
'zte' => 'ZTE', |
519
|
30 |
|
'hmd' => 'HMD', |
520
|
30 |
|
'lt' => 'LT' |
521
|
30 |
|
]; |
522
|
30 |
|
$value = \mb_strtolower($value); |
523
|
30 |
|
return $map[$value] ?? \mb_convert_case($value, MB_CASE_TITLE); |
524
|
|
|
} |
525
|
|
|
} |