Passed
Push — main ( d3029f...a35a1e )
by Will
14:00
created

platforms::getPlatform()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
c 1
b 0
f 0
dl 0
loc 14
ccs 14
cts 14
cp 1
rs 9.8666
cc 1
nc 1
nop 1
crap 1
1
<?php
2
declare(strict_types = 1);
3
namespace hexydec\agentzero;
4
5
class platforms {
6
7
	/**
8
	 * Generates a configuration array for matching platforms
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 60
	public static function get() : array {
13 1
		$fn = [
14 1
			'platformlinux' => function (string $value) : array {
15 16
				if (!\str_starts_with($value, 'Red Hat/') && ($platform = \mb_strstr($value, ' ', true)) !== false) {
16 5
					$value = $platform;
17
				}
18 16
				$parts = \explode('/', $value, 2);
19 16
				if (!isset($parts[1])) {
20 14
					$parts = \explode('-', $value, 2);
21
				}
22 16
				if (!isset($parts[1])) {
23 12
					$parts = \explode(' ', $value, 2);
24
				}
25 16
				return [
26 16
					'type' => 'human',
27 16
					'category' => 'desktop',
28 16
					'kernel' => 'Linux',
29 16
					'platform' => self::getPlatform($parts[0]),
30 16
					'platformversion' => $parts[1] ?? null
31 16
				];
32 1
			},
33 1
			'platformwindows' => function (string $value) : array {
34 47
				$mapping = [
35 47
					'5.0' => '2000',
36 47
					'5.1' => 'XP',
37 47
					'5.2' => 'XP',
38 47
					'6.0' => 'Vista',
39 47
					'6.1' => '7',
40 47
					'6.2' => '8',
41 47
					'6.3' => '8.1',
42 47
					'10.0' => '10'
43 47
				];
44 47
				$version = null;
45 47
				foreach (['Windows NT ', 'Windows '] AS $item) {
46 47
					if (($pos = \mb_stripos($value, $item)) !== false) {
47 47
						$version = \explode(' ', \mb_substr($value, $pos + \mb_strlen($item)))[0];
48 47
						break;
49
					}
50
				}
51 47
				return [
52 47
					'type' => 'human',
53 47
					'category' => 'desktop',
54 47
					'kernel' => 'Windows NT',
55 47
					'platform' => 'Windows',
56 47
					'platformversion' => $mapping[$version] ?? $version
57 47
				];
58 1
			},
59 1
			'android' => function (string $value, int $i, array $tokens) : array {
60 41
				$os = \explode(' ', $value, 3);
61
62
				// skip language
63 41
				if (!empty($tokens[++$i]) && (\strlen($tokens[$i]) === 2 || (\strlen($tokens[$i]) === 5 && \mb_strpos($tokens[$i], '_') === 2))) {
64 2
					$i++;
65
				}
66
67
				// only where the token length is greater than 2, or it doesn't contain a /, or if it does it is Build/
68 41
				$device = empty($tokens[$i]) || \strlen($tokens[$i]) <= 2 || (\str_contains($tokens[$i], '/') && \mb_stripos($tokens[$i], 'Build/') === false) ? [] : devices::getDevice($tokens[$i]);
69 41
				return \array_merge($device, [
70 41
					'type' => 'human',
71 41
					'platform' => 'Android',
72 41
					'platformversion' => isset($os[1]) ? \explode('/', $os[1])[0] : null
73 41
				]);
74 1
			}
75 1
		];
76
77 48
		return [
78
79
			// platforms
80 48
			'PalmSource' => new props('start', fn (string $value) : array => [
81 3
				'type' => 'human',
82 3
				'category' => 'mobile',
83 3
				'platform' => 'PalmOS',
84 3
				'platformversion' => \mb_substr($value, 11) ?: null,
85 3
				'kernel' => 'AMX 68000',
86 3
				'architecture' => 'Arm',
87 3
				'bits' => 32,
88 3
			]),
89 48
			'PalmOS' => new props('start', fn (string $value) : array => [
90 2
				'type' => 'human',
91 2
				'category' => 'mobile',
92 2
				'platform' => 'PalmOS',
93 2
				'platformversion' => \mb_substr($value, 7) ?: null,
94 2
				'kernel' => 'AMX 68000',
95 2
				'architecture' => 'Arm',
96 2
				'bits' => 32,
97 2
			]),
98 48
			'Windows NT ' => new props('any', $fn['platformwindows']),
99 48
			'Windows Phone' => new props('start', function (string $value) : array {
100 3
				$version = \mb_substr($value, 14);
101 3
				return [
102 3
					'type' => 'human',
103 3
					'category' => 'mobile',
104 3
					'platform' => 'Windows Phone',
105 3
					'platformversion' => $version,
106 3
					'kernel' => \intval($version) >= 8 ? 'Windows NT' : 'Windows CE'
107 3
				];
108 48
			}),
109 48
			'Win98' => new props('start', function (string $value, int $i, array $tokens) : array {
110 2
				foreach ($tokens AS $item) {
111 2
					if (\str_starts_with($item, 'PalmSource')) {
112
						return [];
113
					}
114
				}
115 2
				return [
116 2
					'type' => 'human',
117 2
					'category' => 'desktop',
118 2
					'architecture' => 'x86',
119 2
					'bits' => 32,
120 2
					'kernel' => 'MS-DOS',
121 2
					'platform' => 'Windows',
122 2
					'platformversion' => '98'
123 2
				];
124 48
			}),
125 48
			'Win32' => new props('exact', [
126 48
				'type' => 'human',
127 48
				'category' => 'desktop',
128 48
				'architecture' => 'x86',
129 48
				'bits' => 32,
130 48
				'platform' => 'Windows'
131 48
			]),
132 48
			'Win64' => new props('exact', [
133 48
				'type' => 'human',
134 48
				'category' => 'desktop',
135 48
				'bits' => 64,
136 48
				'platform' => 'Windows'
137 48
			]),
138 48
			'WinNT' => new props('start', fn (string $value) : array => [
139 2
				'type' => 'human',
140 2
				'category' => 'desktop',
141 2
				'architecture' => 'x86',
142 2
				'bits' => 32,
143 2
				'kernel' => 'Windows NT',
144 2
				'platform' => 'Windows',
145 2
				'platformversion' => \mb_substr($value, 5)
146 2
			]),
147 48
			'Windows' => new props('any', function (string $value, int $i, array $tokens) use ($fn) : array {
148 48
				foreach ($tokens AS $item) {
149 48
					if (\str_starts_with($item, 'PalmSource')) {
150 2
						return [];
151
					}
152
				}
153 47
				return $fn['platformwindows']($value);
154 48
			}),
155 48
			'MacOS/' => new props('start', fn (string $value) : array => [
156 2
				'type' => 'human',
157 2
				'category' => 'desktop',
158 2
				'vendor' => 'Apple',
159 2
				'platform' => 'MacOS',
160 2
				'platformversion' => \mb_substr($value, 6),
161 2
				'bits' => 64
162 2
			]),
163 48
			'Mac OS X' => new props('any', function (string $value) : array {
164 31
				$version = \str_replace('_', '.', \mb_substr($value, \mb_stripos($value, 'Mac OS X') + 9));
165 31
				$register = $version && \intval(\explode('.', $version)[1] ?? 0) >= 6 ? 64 : null;
166 31
				return [
167 31
					'type' => 'human',
168 31
					'category' => 'desktop',
169 31
					'kernel' => 'Linux',
170 31
					'platform' => 'Mac OS X',
171 31
					'platformversion' => $version === '' ? null : $version,
172 31
					'bits' => $register
173 31
				];
174 48
			}),
175 48
			'AppleTV' => new props('exact', [
176 48
				'type' => 'human',
177 48
				'category' => 'tv',
178 48
				'device' => 'AppleTV',
179 48
				'platform' => 'tvOS',
180 48
				'bits' => 64
181 48
			]),
182 48
			'iOS/' => new props('start', fn (string $value) : array => [
183 2
				'type' => 'human',
184 2
				'category' => 'mobile',
185 2
				'platform' => 'iOS',
186 2
				'platformversion' => \mb_substr($value, 4)
187 2
			]),
188 48
			'iOS ' => new props('start', fn (string $value) : array => [
189 3
				'type' => 'human',
190 3
				'category' => 'mobile',
191 3
				'platform' => 'iOS',
192 3
				'platformversion' => \str_replace('_', '.', \mb_substr($value, 4))
193 3
			]),
194 48
			'iOS' => new props('exact', fn (string $value, int $i, array $tokens) : array => [
195 1
				'type' => 'human',
196 1
				'category' => 'mobile',
197 1
				'platform' => 'iOS',
198 1
				'platformversion' => $tokens[$i+1]
199 1
			]),
200 48
			'CrOS' => new props('start', function (string $value) : array {
201 4
				$parts = \explode(' ', $value);
202 4
				return [
203 4
					'type' => 'human',
204 4
					'category' => 'desktop',
205 4
					'platform' => 'Chrome OS',
206 4
					'platformversion' => $parts[2] ?? null
207 4
				];
208 48
			}),
209 48
			'Kindle/' => new props('start', fn (string $value) : array => [
210 2
				'type' => 'human',
211 2
				'category' => 'ebook',
212 2
				'platform' => 'Kindle',
213 2
				'platformversion' => \mb_substr($value, 7)
214 2
			]),
215 48
			'Tizen' => new props('start', function (string $value) : array {
216 1
				$parts = \explode(' ', $value, 2);
217 1
				return [
218 1
					'type' => 'human',
219 1
					'category' => 'desktop',
220 1
					'kernel' => 'Linux',
221 1
					'platform' => 'Tizen',
222 1
					'platformversion' => $parts[1] ?? null
223 1
				];
224 48
			}),
225 48
			'KAIOS/' => new props('start', function (string $value, int $i, array $tokens) : array {
226
227
				// find device
228 1
				foreach ($tokens AS $i => $item) {
229 1
					if ($item === 'Mobile' && !\str_starts_with($tokens[$i++] ?? 'rv:', 'rv:')) {
230 1
						if (\str_contains($tokens[$i], '/')) {
231 1
							$parts = \explode('/', $tokens[$i]);
232
						} else {
233 1
							$parts = \explode(' ', \str_replace('_', ' ', $tokens[$i]), 2);
234
						}
235 1
						break;
236
					}
237
				}
238 1
				return [
239 1
					'type' => 'human',
240 1
					'category' => 'mobile',
241 1
					'kernel' => 'Linux',
242 1
					'architecture' => 'Arm',
243 1
					'platform' => 'KaiOS',
244 1
					'platformversion' => \mb_substr($value, 6),
245 1
					'vendor' => !empty($parts[0]) ? devices::getVendor($parts[0]) : null,
246 1
					'device' => $parts[1] ?? null,
247 1
					'build' => $parts[2] ?? null
248 1
				];
249 48
	}		),
250 48
			'Ubuntu' => new props('start', $fn['platformlinux']),
251 48
			'Kubuntu' => new props('start', $fn['platformlinux']),
252 48
			'Mint' => new props('start', $fn['platformlinux']),
253 48
			'SUSE' => new props('start', $fn['platformlinux']),
254 48
			'Red Hat/' => new props('start', $fn['platformlinux']),
255 48
			'Debian' => new props('start', $fn['platformlinux']),
256 48
			'Darwin' => new props('start', $fn['platformlinux']),
257 48
			'Fedora' => new props('start', $fn['platformlinux']),
258 48
			'CentOS' => new props('start', $fn['platformlinux']),
259 48
			'Rocky' => new props('start', $fn['platformlinux']),
260 48
			'Alma' => new props('start', $fn['platformlinux']),
261 48
			'Gentoo' => new props('start', $fn['platformlinux']),
262 48
			'Slackware' => new props('start', $fn['platformlinux']),
263 48
			'OpenSUSE' => new props('start', $fn['platformlinux']),
264 48
			'FreeBSD' => new props('start', $fn['platformlinux']),
265 48
			'OpenBSD' => new props('start', $fn['platformlinux']),
266 48
			'ArchLinux' => new props('exact', fn () : array => [
267 1
				'type' => 'human',
268 1
				'category' => 'desktop',
269 1
				'kernel' => 'Linux',
270 1
				'platform' => 'Arch',
271 1
			]),
272 48
			'Arch' => new props('exact', fn () : array => [
273 1
				'type' => 'human',
274 1
				'category' => 'desktop',
275 1
				'kernel' => 'Linux',
276 1
				'platform' => 'Arch',
277 1
			]),
278 48
			'Web0S' => new props('exact', $fn['platformlinux']),
279 48
			'webOSTV' => new props('exact', [
280 48
				'type' => 'human',
281 48
				'category' => 'tv',
282 48
				'kernel' => 'Linux',
283 48
				'platform' => 'WebOS'
284 48
			]),
285 48
			'WEBOS' => new props('start', fn (string $value) : array => [
286 2
				'type' => 'human',
287 2
				'category' => 'tv',
288 2
				'kernel' => 'Linux',
289 2
				'platform' => 'WebOS',
290 2
				'platformversion' => \mb_substr($value, 5)
291 2
			]),
292 48
			'SunOS' => new props('start', [
293 48
				'type' => 'human',
294 48
				'category' => 'desktop',
295 48
				'kernel' => 'unix',
296 48
				'platform' => 'Solaris',
297 48
			]),
298 48
			'AmigaOS' => new props('any', function (string $value) : array {
299 3
				if (($pos = \mb_stripos($value, 'AmigaOS')) !== false) {
300 3
					$value = \mb_substr($value, $pos);
301
				}
302 3
				$parts = \explode(' ', $value, 2);
303 3
				return [
304 3
					'type' => 'human',
305 3
					'category' => 'desktop',
306 3
					'kernel' => 'Exec',
307 3
					'platform' => 'AmigaOS',
308 3
					'platformversion' => isset($parts[1]) && \strspn($parts[1], '0123456789.-_') === \strlen($parts[1]) ? $parts[1] : null
309 3
				];
310 48
			}),
311 48
			'Fuchsia' => new props('exact', function (string $value, int $i, array $tokens) : array {
312 1
				$os = \explode(' ', $tokens[++$i], 2);
313 1
				return [
314 1
					'type' => 'human',
315 1
					'category' => 'mobile',
316 1
					'kernel' => 'Zircon',
317 1
					'platform' => 'Fuchsia',
318 1
					'platformversion' => isset($os[1]) && \strspn($os[1], '0123456789.-_', \strlen($os[0])) === \strlen($os[1]) ? $os[1] : null
319 1
				];
320 48
			}),
321 48
			'Maemo' => new props('exact', function (string $value, int $i, array $tokens) : array {
322 1
				$os = \explode(' ', $tokens[++$i], 2);
323 1
				return [
324 1
					'type' => 'human',
325 1
					'category' => 'mobile',
326 1
					'kernel' => 'Linux',
327 1
					'platform' => 'Maemo',
328 1
					'platformversion' => isset($os[1]) && \strspn($os[1], '0123456789.-_', \strlen($os[0])) === \strlen($os[1]) ? $os[1] : null
329 1
				];
330 48
			}),
331 48
			'J2ME/MIDP' => new props('exact', fn (string $value) : array => [
332 3
				'type' => 'human',
333 3
				'category' => 'mobile',
334 3
				'kernel' => 'Java VM',
335 3
				'platform' => $value
336 3
			]),
337 48
			'Haiku' => new props('any', function (string $value) : array {
338 3
				$parts = \explode('/', $value, 2);
339 3
				return [
340 3
					'type' => 'human',
341 3
					'category' => 'desktop',
342 3
					'kernel' => 'Haiku',
343 3
					'platform' => 'Haiku',
344 3
					'platformversion' => $parts[1] ?? null
345 3
				];
346 48
			}),
347 48
			'BeOS' => new props('start', function (string $value) : array {
348 1
				$parts = \explode('/', $value, 2);
349 1
				return [
350 1
					'type' => 'human',
351 1
					'category' => 'desktop',
352 1
					'kernel' => 'BeOS',
353 1
					'platform' => 'BeOS',
354 1
					'platformversion' => $parts[1] ?? null
355 1
				];
356 48
			}),
357 48
			'Android' => new props('exact', $fn['android']),
358 48
			'Android/' => new props('start', fn (string $value) : array => [
359 1
				'type' => 'human',
360 1
				'platform' => 'Android',
361 1
				'platformversion' => \explode('/', $value, 3)[1] ?: null
362 1
			]),
363 48
			'Android ' => new props('start', $fn['android']),
364 48
			'Linux' => new props('any', function (string $value, int $i, array $tokens) : array {
365 60
				return [
366 60
					'kernel' => 'Linux',
367 60
					'platform' => 'Linux',
368 60
					'platformversion' => \str_contains($tokens[$i + 1] ?? '', '.') && \strspn($tokens[$i + 1], '0123456789.') >= 3 ? \explode(' ', $tokens[$i + 1])[0] : null
369 60
				];
370 48
			}),
371 48
			'X11' => new props('exact', function (string $value, int $i, array $tokens) : array {
372 32
				$os = \explode(' ', $tokens[++$i] ?? '', 2);
373 32
				return [
374 32
					'category' => 'desktop',
375 32
					'kernel' => 'Linux',
376 32
					'platform' => $os[0] ?: 'X11',
377 32
					'platformversion' => isset($os[1]) && \strspn($os[1], '0123456789.-_', \strlen($os[0])) === \strlen($os[1]) ? $os[1] : null
378 32
				];
379 48
			}),
380 48
			'OS/2' => new props('exact', [
381 48
				'category' => 'desktop',
382 48
				'platform' => 'OS/2'
383 48
			]),
384 48
			'Version/' => new props('start', fn (string $value) : array => [
385 45
				'platformversion' => \mb_substr($value, 8)
386 45
			])
387 48
		];
388
	}
389
390 23
	public static function getPlatform(string $value) : string {
391 23
		$map = [
392 23
			'webos' => 'WebOS',
393 23
			'web0s' => 'WebOS',
394 23
			'j2me/midp' => 'J2ME/MIDP',
395 23
			'centos' => 'CentOS',
396 23
			'suse' => 'SUSE',
397 23
			'freebsd' => 'FreeBSD',
398 23
			'openbsd' => 'OpenBSD',
399 23
			'netbsd' => 'NetBSD',
400 23
			'opensuse' => 'OpenSUSE'
401 23
		];
402 23
		$value = \mb_strtolower($value);
403 23
		return $map[$value] ?? \mb_convert_case($value, MB_CASE_TITLE);
404
	}
405
}