Passed
Push — main ( 4dd032...ebaf8d )
by Will
03:20
created

platforms::get()   F

Complexity

Conditions 46
Paths 1

Size

Total Lines 401
Code Lines 317

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 376
CRAP Score 46

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 46
eloc 317
c 3
b 0
f 0
nc 1
nop 0
dl 0
loc 401
ccs 376
cts 377
cp 0.9973
crap 46
rs 3.3333

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
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 61
	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 48
				$mapping = [
35 48
					'5.0' => '2000',
36 48
					'5.1' => 'XP',
37 48
					'5.2' => 'XP',
38 48
					'6.0' => 'Vista',
39 48
					'6.1' => '7',
40 48
					'6.2' => '8',
41 48
					'6.3' => '8.1',
42 48
					'10.0' => '10'
43 48
				];
44 48
				$version = null;
45 48
				foreach (['Windows NT ', 'Windows '] AS $item) {
46 48
					if (($pos = \mb_stripos($value, $item)) !== false) {
47 48
						$version = \explode(' ', \mb_substr($value, $pos + \mb_strlen($item)))[0];
48 48
						break;
49
					}
50
				}
51 48
				return [
52 48
					'type' => 'human',
53 48
					'category' => 'desktop',
54 48
					'kernel' => 'Windows NT',
55 48
					'platform' => 'Windows',
56 48
					'platformversion' => $mapping[$version] ?? $version
57 48
				];
58 1
			},
59 1
			'android' => function (string $value, int $i, array $tokens) : array {
60 42
				$os = \explode(' ', $value, 3);
61
62
				// skip language
63 42
				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 42
				$device = empty($tokens[$i]) || \strlen($tokens[$i]) <= 2 || (\str_contains($tokens[$i], '/') && \mb_stripos($tokens[$i], 'Build/') === false) ? [] : devices::getDevice($tokens[$i]);
69 42
				return \array_merge($device, [
70 42
					'type' => 'human',
71 42
					'platform' => 'Android',
72 42
					'platformversion' => isset($os[1]) ? \explode('/', $os[1])[0] : null
73 42
				]);
74 1
			}
75 1
		];
76
77 49
		return [
78
79
			// platforms
80 49
			'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 49
			'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 49
			'Windows NT ' => new props('any', $fn['platformwindows']),
99 49
			'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 49
			}),
109 49
			'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 49
			}),
125 49
			'Win32' => new props('exact', [
126 49
				'type' => 'human',
127 49
				'category' => 'desktop',
128 49
				'architecture' => 'x86',
129 49
				'bits' => 32,
130 49
				'platform' => 'Windows'
131 49
			]),
132 49
			'Win64' => new props('exact', [
133 49
				'type' => 'human',
134 49
				'category' => 'desktop',
135 49
				'bits' => 64,
136 49
				'platform' => 'Windows'
137 49
			]),
138 49
			'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 49
			'Windows' => new props('any', function (string $value, int $i, array $tokens) use ($fn) : array {
148 49
				foreach ($tokens AS $item) {
149 49
					if (\str_starts_with($item, 'PalmSource')) {
150 2
						return [];
151
					}
152
				}
153 48
				return $fn['platformwindows']($value);
154 49
			}),
155 49
			'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 49
			'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 49
			}),
175 49
			'AppleTV' => new props('exact', [
176 49
				'type' => 'human',
177 49
				'category' => 'tv',
178 49
				'device' => 'AppleTV',
179 49
				'platform' => 'tvOS',
180 49
				'bits' => 64
181 49
			]),
182 49
			'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 49
			'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 49
			'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] ?? null
199 1
			]),
200 49
			'iPadOS' => new props('exact', fn (string $value, int $i, array $tokens) : array => [
201 1
				'type' => 'human',
202 1
				'category' => 'tablet',
203 1
				'vendor' => 'Apple',
204 1
				'device' => 'iPad',
205 1
				'platform' => 'iOS',
206 1
				'platformversion' => $tokens[$i+1] ?? null
207 1
			]),
208 49
			'CrOS' => new props('start', function (string $value) : array {
209 4
				$parts = \explode(' ', $value);
210 4
				return [
211 4
					'type' => 'human',
212 4
					'category' => 'desktop',
213 4
					'platform' => 'Chrome OS',
214 4
					'platformversion' => $parts[2] ?? null
215 4
				];
216 49
			}),
217 49
			'Kindle/' => new props('start', fn (string $value) : array => [
218 2
				'type' => 'human',
219 2
				'category' => 'ebook',
220 2
				'platform' => 'Kindle',
221 2
				'platformversion' => \mb_substr($value, 7)
222 2
			]),
223 49
			'Tizen' => new props('start', function (string $value) : array {
224 1
				$parts = \explode(' ', $value, 2);
225 1
				return [
226 1
					'type' => 'human',
227 1
					'category' => 'desktop',
228 1
					'kernel' => 'Linux',
229 1
					'platform' => 'Tizen',
230 1
					'platformversion' => $parts[1] ?? null
231 1
				];
232 49
			}),
233 49
			'KAIOS/' => new props('start', function (string $value, int $i, array $tokens) : array {
234
235
				// find device
236 1
				foreach ($tokens AS $i => $item) {
237 1
					if ($item === 'Mobile' && !\str_starts_with($tokens[$i++] ?? 'rv:', 'rv:')) {
238 1
						if (\str_contains($tokens[$i], '/')) {
239 1
							$parts = \explode('/', $tokens[$i]);
240
						} else {
241 1
							$parts = \explode(' ', \str_replace('_', ' ', $tokens[$i]), 2);
242
						}
243 1
						break;
244
					}
245
				}
246 1
				return [
247 1
					'type' => 'human',
248 1
					'category' => 'mobile',
249 1
					'kernel' => 'Linux',
250 1
					'architecture' => 'Arm',
251 1
					'platform' => 'KaiOS',
252 1
					'platformversion' => \mb_substr($value, 6),
253 1
					'vendor' => !empty($parts[0]) ? devices::getVendor($parts[0]) : null,
254 1
					'device' => $parts[1] ?? null,
255 1
					'build' => $parts[2] ?? null
256 1
				];
257 49
	}		),
258 49
			'Ubuntu' => new props('start', $fn['platformlinux']),
259 49
			'Kubuntu' => new props('start', $fn['platformlinux']),
260 49
			'Mint' => new props('start', $fn['platformlinux']),
261 49
			'SUSE' => new props('start', $fn['platformlinux']),
262 49
			'Red Hat/' => new props('start', $fn['platformlinux']),
263 49
			'Debian' => new props('start', $fn['platformlinux']),
264 49
			'Darwin' => new props('start', $fn['platformlinux']),
265 49
			'Fedora' => new props('start', $fn['platformlinux']),
266 49
			'CentOS' => new props('start', $fn['platformlinux']),
267 49
			'Rocky' => new props('start', $fn['platformlinux']),
268 49
			'Alma' => new props('start', $fn['platformlinux']),
269 49
			'Gentoo' => new props('start', $fn['platformlinux']),
270 49
			'Slackware' => new props('start', $fn['platformlinux']),
271 49
			'OpenSUSE' => new props('start', $fn['platformlinux']),
272 49
			'FreeBSD' => new props('start', $fn['platformlinux']),
273 49
			'OpenBSD' => new props('start', $fn['platformlinux']),
274 49
			'ArchLinux' => new props('exact', fn () : array => [
275 1
				'type' => 'human',
276 1
				'category' => 'desktop',
277 1
				'kernel' => 'Linux',
278 1
				'platform' => 'Arch',
279 1
			]),
280 49
			'Arch' => new props('exact', fn () : array => [
281 1
				'type' => 'human',
282 1
				'category' => 'desktop',
283 1
				'kernel' => 'Linux',
284 1
				'platform' => 'Arch',
285 1
			]),
286 49
			'Web0S' => new props('exact', $fn['platformlinux']),
287 49
			'webOSTV' => new props('exact', [
288 49
				'type' => 'human',
289 49
				'category' => 'tv',
290 49
				'kernel' => 'Linux',
291 49
				'platform' => 'WebOS'
292 49
			]),
293 49
			'WEBOS' => new props('start', fn (string $value) : array => [
294 2
				'type' => 'human',
295 2
				'category' => 'tv',
296 2
				'kernel' => 'Linux',
297 2
				'platform' => 'WebOS',
298 2
				'platformversion' => \mb_substr($value, 5)
299 2
			]),
300 49
			'Roku ' => new props('start', function (string $value, int $i, array $tokens) : array {
301 1
				$app = \str_contains($tokens[$i - 1] ?? '', '/') ? \explode('/', $tokens[$i - 1], 2) : null;
302 1
				return \array_merge(
303 1
					[
304 1
						'type' => 'human',
305 1
						'category' => 'tv',
306 1
						'platform' => 'Roku',
307 1
						'platformversion' => \mb_substr($value, 5),
308 1
						'app' => $app[0] ?? null,
309 1
						'appname' => $app[0] ?? null,
310 1
						'appversion' => $app[1] ?? null,
311 1
					],
312 1
					isset($tokens[$i + 2]) ? devices::getDevice($tokens[$i + 2]) : []
313 1
				);
314 49
			}),
315 49
			'SunOS' => new props('start', [
316 49
				'type' => 'human',
317 49
				'category' => 'desktop',
318 49
				'kernel' => 'unix',
319 49
				'platform' => 'Solaris',
320 49
			]),
321 49
			'AmigaOS' => new props('any', function (string $value) : array {
322 3
				if (($pos = \mb_stripos($value, 'AmigaOS')) !== false) {
323 3
					$value = \mb_substr($value, $pos);
324
				}
325 3
				$parts = \explode(' ', $value, 2);
326 3
				return [
327 3
					'type' => 'human',
328 3
					'category' => 'desktop',
329 3
					'kernel' => 'Exec',
330 3
					'platform' => 'AmigaOS',
331 3
					'platformversion' => isset($parts[1]) && \strspn($parts[1], '0123456789.-_') === \strlen($parts[1]) ? $parts[1] : null
332 3
				];
333 49
			}),
334 49
			'Fuchsia' => new props('exact', function (string $value, int $i, array $tokens) : array {
335 1
				$os = \explode(' ', $tokens[++$i], 2);
336 1
				return [
337 1
					'type' => 'human',
338 1
					'category' => 'mobile',
339 1
					'kernel' => 'Zircon',
340 1
					'platform' => 'Fuchsia',
341 1
					'platformversion' => isset($os[1]) && \strspn($os[1], '0123456789.-_', \strlen($os[0])) === \strlen($os[1]) ? $os[1] : null
342 1
				];
343 49
			}),
344 49
			'Maemo' => new props('exact', function (string $value, int $i, array $tokens) : array {
345 1
				$os = \explode(' ', $tokens[++$i], 2);
346 1
				return [
347 1
					'type' => 'human',
348 1
					'category' => 'mobile',
349 1
					'kernel' => 'Linux',
350 1
					'platform' => 'Maemo',
351 1
					'platformversion' => isset($os[1]) && \strspn($os[1], '0123456789.-_', \strlen($os[0])) === \strlen($os[1]) ? $os[1] : null
352 1
				];
353 49
			}),
354 49
			'J2ME/MIDP' => new props('exact', fn (string $value) : array => [
355 3
				'type' => 'human',
356 3
				'category' => 'mobile',
357 3
				'kernel' => 'Java VM',
358 3
				'platform' => $value
359 3
			]),
360 49
			'Haiku' => new props('any', function (string $value) : array {
361 3
				$parts = \explode('/', $value, 2);
362 3
				return [
363 3
					'type' => 'human',
364 3
					'category' => 'desktop',
365 3
					'kernel' => 'Haiku',
366 3
					'platform' => 'Haiku',
367 3
					'platformversion' => $parts[1] ?? null
368 3
				];
369 49
			}),
370 49
			'BeOS' => new props('start', function (string $value) : array {
371 1
				$parts = \explode('/', $value, 2);
372 1
				return [
373 1
					'type' => 'human',
374 1
					'category' => 'desktop',
375 1
					'kernel' => 'BeOS',
376 1
					'platform' => 'BeOS',
377 1
					'platformversion' => $parts[1] ?? null
378 1
				];
379 49
			}),
380 49
			'Android' => new props('exact', $fn['android']),
381 49
			'Android/' => new props('start', fn (string $value) : array => [
382 2
				'type' => 'human',
383 2
				'platform' => 'Android',
384 2
				'platformversion' => \explode('/', $value, 3)[1] ?: null
385 2
			]),
386 49
			'Android ' => new props('start', $fn['android']),
387 49
			'Android-' => new props('start', $fn['android']),
388 49
			'Linux' => new props('any', function (string $value, int $i, array $tokens) : array {
389 61
				return [
390 61
					'kernel' => 'Linux',
391 61
					'platform' => 'Linux',
392 61
					'platformversion' => \str_contains($tokens[$i + 1] ?? '', '.') && \strspn($tokens[$i + 1], '0123456789.') >= 3 ? \explode(' ', $tokens[$i + 1])[0] : null
393 61
				];
394 49
			}),
395 49
			'X11' => new props('exact', function (string $value, int $i, array $tokens) : array {
396 32
				$os = \explode(' ', $tokens[++$i] ?? '', 2);
397 32
				return [
398 32
					'category' => 'desktop',
399 32
					'kernel' => 'Linux',
400 32
					'platform' => $os[0] ?: 'X11',
401 32
					'platformversion' => isset($os[1]) && \strspn($os[1], '0123456789.-_', \strlen($os[0])) === \strlen($os[1]) ? $os[1] : null
402 32
				];
403 49
			}),
404 49
			'OS/2' => new props('exact', [
405 49
				'category' => 'desktop',
406 49
				'platform' => 'OS/2'
407 49
			]),
408 49
			'Version/' => new props('start', fn (string $value) : array => [
409 46
				'platformversion' => \mb_substr($value, 8)
410 46
			]),
411 49
			'platformVersion/' => new props('start', fn (string $value) : array => [
412 2
				'platformversion' => \mb_substr($value, 16)
413 2
			]),
414 49
		];
415
	}
416
417 24
	public static function getPlatform(string $value) : string {
418 24
		$map = [
419 24
			'webos' => 'WebOS',
420 24
			'web0s' => 'WebOS',
421 24
			'j2me/midp' => 'J2ME/MIDP',
422 24
			'centos' => 'CentOS',
423 24
			'suse' => 'SUSE',
424 24
			'freebsd' => 'FreeBSD',
425 24
			'openbsd' => 'OpenBSD',
426 24
			'netbsd' => 'NetBSD',
427 24
			'opensuse' => 'OpenSUSE',
428 24
			'iphone' => 'iOS'
429 24
		];
430 24
		$value = \mb_strtolower($value);
431 24
		return $map[$value] ?? \mb_convert_case($value, MB_CASE_TITLE);
432
	}
433
}