Passed
Push — main ( 03a93c...274053 )
by Will
13:21
created

apps   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 385
Duplicated Lines 0 %

Test Coverage

Coverage 97.47%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 35
eloc 270
c 1
b 0
f 0
dl 0
loc 385
ccs 347
cts 356
cp 0.9747
rs 9.6

1 Method

Rating   Name   Duplication   Size   Complexity  
F get() 0 378 35
1
<?php
2
declare(strict_types = 1);
3
namespace hexydec\agentzero;
4
5
/**
6
 * @phpstan-import-type MatchConfig from config
7
 */
8
class apps {
9
10
	/**
11
	 * Generates a configuration array for matching apps
12
	 * 
13
	 * @return MatchConfig An array with keys representing the string to match, and a value of an array containing parsing and output settings
0 ignored issues
show
Bug introduced by
The type hexydec\agentzero\MatchConfig was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
	 */
15 44
	public static function get() : array {
16 1
		$fn = [
17 1
			'appslash' => function (string $value, int $i, array $tokens, string $match) : ?array {
18 44
				if (\mb_stripos($value, 'AppleWebKit') !== 0 && !\str_contains($value, '://')) {
19 19
					$parts = \explode('/', $value, 4);
20 19
					$offset = isset($parts[2]) ? 1 : 0;
21 19
					$map = [
22 19
						'YaApp_iOS' => 'Yandex',
23 19
						'YaApp_Android' => 'Yandex',
24 19
						'YaSearchApp' => 'Yandex',
25 19
						'YaBrowser' => 'Yandex',
26 19
						'LinkedInApp' => 'LinkedIn',
27 19
						'[LinkedInApp]' => 'LinkedIn',
28 19
						'GoogleApp' => 'Google',
29 19
						'com.zhiliaoapp.musically' => 'TikTok',
30 19
						'com.google.android.apps.searchlite' => 'Google (Lite)',
31 19
						'com.google.android.googlequicksearchbox' => 'Google (Quick Search Box)',
32 19
						'com.google.photos' => 'Google Photos',
33 19
						'com.google.ios.youtube' => 'YouTube',
34 19
						'com.google.GoogleMobile' => 'Google',
35 19
						'AlohaBrowserApp' => 'Aloha'
36 19
					];
37 19
					$app = $parts[0 + $offset];
38 19
					if (\mb_stripos($app, \rtrim($match, '/')) !== false) { // check the match is before the slash
39 19
						return [
40 19
							'type' => 'human',
41 19
							'app' => $map[$app] ?? $app,
42 19
							'appversion' => $parts[1 + $offset] ?? null
43 19
						];
44
					}
45
				}
46 37
				return null;
47 1
			},
48 1
			'langslash' => function (string $value) : array {
49 6
				$parts = \explode('-', \str_replace('_', '-', \explode('/', $value, 2)[1]), 4);
50 6
				$suffix = $parts[2] ?? $parts[1] ?? null;
51 6
				return [
52 6
					'language' => \strtolower($parts[0]).($suffix !== null ? '-'.\strtoupper($suffix) : '')
53 6
				];
54 1
			}
55 1
		];
56 3
		return [
57 3
			'OcIdWebView' => [
58 3
				'match' => 'exact',
59 3
				'categories' => function (string $value, int $i, array $tokens) : array {
0 ignored issues
show
Unused Code introduced by
The parameter $tokens is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

59
				'categories' => function (string $value, int $i, /** @scrutinizer ignore-unused */ array $tokens) : array {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $i is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

59
				'categories' => function (string $value, /** @scrutinizer ignore-unused */ int $i, array $tokens) : array {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
60 1
					$data = [
61 1
						'app' => $value
62 1
					];
63 1
					return $data;
64 3
				}
65 3
			],
66 3
			'com.google.GoogleMobile/' => [
67 3
				'match' => 'start',
68 3
				'categories' => function (string $value, int $i, array $tokens, string $match) use ($fn) : array {
69
					return \array_merge($fn['appslash']($value, $i, $tokens, $match), [
70
						'category' => 'mobile'
71
					]);
72 3
				}
73 3
			],
74 3
			'com.google.' => [
75 3
				'match' => 'start',
76 3
				'categories' => $fn['appslash']
77 3
			],
78 3
			'Instagram' => [
79 3
				'match' => 'any',
80 3
				'categories' => function (string $value, int $i, array $tokens) : array {
81 6
					$parts = \explode(' ', $value, 4);
82 6
					$data = [
83 6
						'type' => 'human',
84 6
						'app' => 'Instagram',
85 6
						'appversion' => $parts[1] ?? null,
86 6
						'platform' => empty($parts[2]) ? null : platforms::getPlatform($parts[2])
87 6
					];
88 6
					foreach (\array_slice($tokens, $i + 1) AS $key => $item) {
89 6
						if (($ipados = \str_starts_with($item, 'iPadOS')) || \str_starts_with($item, 'iOS ')) {
90 2
							$data['kernel'] = 'Linux';
91 2
							$data['platform'] = 'iOS';
92 2
							$data['platformversion'] = \str_replace('_', '.', \mb_substr($item, $ipados ? 7 : 4));
93 2
							$data['density'] = \floatval(\mb_substr($item, 6));
94 6
						} elseif (($iphone = \str_starts_with($item, 'iPhone')) || ($ipad = \str_starts_with($item, 'iPad')) || \str_starts_with($item, 'iPod')) {
95 2
							$data['vendor'] = 'Apple';
96 2
							$data['category'] = empty($ipad) ? 'mobile' : 'tablet';
97 2
							$data['device'] = $iphone ? 'iPhone' : ($ipad ? 'iPad' : 'iPod');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ipad does not seem to be defined for all execution paths leading up to this point.
Loading history...
98 2
							$data['model'] = \str_replace(',', '.', \mb_substr($item, $iphone ? 6 : 4));
99 2
							$data['architecture'] = 'arm';
100 2
							$data['bits'] = 64;
101 6
						} elseif (\str_starts_with($item, 'scale=')) {
102 2
							$data['density'] = \floatval(\mb_substr($item, 6));
103 6
						} elseif (\str_ends_with($item, 'dpi')) {
104 5
							$data['dpi'] = \intval(\mb_substr($item, 0, -3));
105 6
						} elseif (\str_contains($item, 'x') && \strspn($item, '0123456789x') === \strlen($item)) {
106 6
							list($data['width'], $data['height']) = \array_map('intval', \explode('x', $item, 2));
107
108
							// get device when the UA string starts with "Instagram"
109 6
							if ($i === 0 && !isset($data['vendor'])) {
110 1
								$device = [
111 1
									\trim(\mb_strstr($tokens[$key + 2] ?? '', '/') ?: $tokens[$key + 2] ?? '', '/ '), // sometimes the vendor name has a / with the correct name after
112 1
									$tokens[$key + 3] ?? null
113 1
								];
114
115
								// remove duplicated name
116 1
								if ($device[1] !== null && \mb_stripos($device[1], $device[0]) === 0) {
117 1
									unset($device[0]);
118
								}
119 1
								$data = \array_merge($data, devices::getDevice(\implode(' ', \array_filter($device))));
120 1
								break;
121
							}
122
						}
123
					}
124 6
					return $data;
125 3
				}
126 3
			],
127 3
			'imoAndroid/' => [
128 3
				'match' => 'start',
129 3
				'categories' => fn (string $value, int $i, array $tokens) : array => \array_merge(
130 3
					isset($tokens[$i + 3]) ? devices::getDevice($tokens[$i + 3]) : [],
131 3
					[
132 3
						'app' => 'imo',
133 3
						'appversion' => \ltrim(\mb_strstr($value, '/'), '/'),
134 3
						'platform' => 'Android',
135 3
						'platformversion' => $tokens[$i + 1] ?? null,
136 3
						'cpu' => $tokens[$i + 11] ?? null,
137 3
						'vendor' => isset($tokens[$i + 4]) ? devices::getVendor($tokens[$i + 4]) : null
138 3
					]
139 3
				)
140 3
			],
141 3
			'GSA/' => [
142 3
				'match' => 'any',
143 3
				'categories' => fn (string $value) : array => [
144 3
					'app' => 'Google',
145 3
					'appversion' => \mb_substr($value, 4)
146 3
				]
147 3
			],
148 3
			'DuckDuckGo/' => [
149 3
				'match' => 'start',
150 3
				'categories' => $fn['appslash']
151 3
			],
152 3
			'FlipboardProxy/' => [
153 3
				'match' => 'start',
154 3
				'categories' => $fn['appslash']
155 3
			],
156 3
			'Emacs/' => [
157 3
				'match' => 'start',
158 3
				'categories' => $fn['appslash']
159 3
			],
160 3
			'AndroidDownloadManager/' => [
161 3
				'match' => 'start',
162 3
				'categories' => $fn['appslash']
163 3
			],
164 3
			'Google-Read-Aloud' => [
165 3
				'match' => 'exact',
166 3
				'categories' => [
167 3
					'type' => 'human',
168 3
					'app' => 'Google-Read-Aloud'
169 3
				]
170 3
			],
171 3
			'Zoom ' => [
172 3
				'match' => 'start',
173 3
				'categories' => fn (string $value) : array => [
174 1
					'app' => 'Zoom',
175 1
					'appversion' => \mb_substr($value, 5)
176 1
				]
177 3
			],
178 3
			'OculusBrowser/' => [
179 3
				'match' => 'start',
180 3
				'categories' => $fn['appslash']
181 3
			],
182 3
			'YaBrowser/' => [
183 3
				'match' => 'start',
184 3
				'categories' => $fn['appslash']
185 3
			],
186 3
			'choqok/' => [
187 3
				'match' => 'start',
188 3
				'categories' => $fn['appslash']
189 3
			],
190 3
			'PowerShell/' => [
191 3
				'match' => 'start',
192 3
				'categories' => $fn['appslash']
193 3
			],
194 3
			'Quora ' => [
195 3
				'match' => 'start',
196 3
				'categories' => fn (string $value) : array => [
197
					'type' => 'human',
198
					'app' => 'Quora',
199
					'appversion' => \explode(' ', $value, 3)[1]
200
				]
201 3
			],
202 3
			'AmazonKidsBrowser/' => [
203 3
				'match' => 'start',
204 3
				'categories' => $fn['appslash']
205 3
			],
206 3
			'Viber/' => [
207 3
				'match' => 'start',
208 3
				'categories' => $fn['appslash']
209 3
			],
210
211
			// special parser for Facebook app because it is completely different to any other
212 3
			'FBAN/' => [
213 3
				'match' => 'any',
214 3
				'categories' => function (string $value) : array {
215 4
					$map = [
216 4
						'FBAN/MessengerLiteForiOS' => [
217 4
							'type' => 'human',
218 4
							'app' => 'Facebook Messenger',
219 4
							'platform' => 'iOS'
220 4
						],
221 4
						'FBAN/FB4A' => [
222 4
							'type' => 'human',
223 4
							'app' => 'Facebook',
224 4
							'platform' => 'Android'
225 4
						],
226 4
						'FBAN/FBIOS' => [
227 4
							'type' => 'human',
228 4
							'app' => 'Facebook',
229 4
							'platform' => 'iOS'
230 4
						],
231 4
						'FBAN/FB4FireTV' => [
232 4
							'type' => 'human',
233 4
							'category' => 'tv',
234 4
							'app' => 'Facebook',
235 4
							'platform' => 'Android'
236 4
						],
237 4
						'FBAN/MessengerDesktop' => [
238 4
							'type' => 'human',
239 4
							'category' => 'desktop',
240 4
							'app' => 'Facebook Messenger'
241 4
						],
242 4
						'FacebookCanvasDesktop FBAN/GamesWindowsDesktopApp' => [
243 4
							'type' => 'human',
244 4
							'platform' => 'Windows',
245 4
							'category' => 'desktop',
246 4
							'app' => 'Facebook Gamesroom'
247 4
						]
248 4
					];
249 4
					return $map[$value] ?? [
250 4
						'app' => 'Facebook',
251 4
						'type' => 'human'
252
					];
253 3
				}
254 3
			],
255 3
			'FB_IAB/' => [
256 3
				'match' => 'start',
257 3
				'categories' => [
258 3
					'app' => 'Facebook'
259 3
				]
260 3
			],
261 3
			'FBAV/' => [
262 3
				'match' => 'start',
263 3
				'categories' => fn (string $value) : array => [
264 8
					'appversion' => \mb_substr($value, 5)
265 8
				]
266 3
			],
267 3
			'FBMF/' => [
268 3
				'match' => 'start',
269 3
				'categories' => fn (string $value) : array => [
270 1
					'vendor' => devices::getVendor(\mb_substr($value, 5))
271 1
				]
272 3
			],
273 3
			'FBDV/' => [
274 3
				'match' => 'start',
275 3
				'categories' => fn (string $value) : array => devices::getDevice(\mb_substr($value, 5))
276 3
			],
277 3
			'FBMD/' => [
278 3
				'match' => 'start',
279 3
				'categories' => fn (string $value) : array => [
280 2
					'model' => \mb_substr($value, 5)
281 2
				]
282 3
			],
283 3
			'FBLC/' => [
284 3
				'match' => 'start',
285 3
				'categories' => $fn['langslash']
286 3
			],
287 3
			'FBDM/' => [
288 3
				'match' => 'start',
289 3
				'categories' => function (string $value) : array {
290 1
					$data = [];
291 1
					foreach (\explode(',', \trim(\mb_substr($value, 5), '{}')) AS $item) {
292 1
						$parts = \explode('=', $item);
293 1
						if (!empty($parts[1])) {
294 1
							if (\is_numeric($parts[1])) {
295 1
								$parts[1] = \str_contains($parts[1], '.') ? \floatval($parts[1]) : \intval($parts[1]);
296
							}
297 1
							$data[$parts[0]] = $parts[1];
298
						}
299
					}
300 1
					return $data;
301 3
				}
302 3
			],
303 3
			'width=' => [
304 3
				'match' => 'start',
305 3
				'categories' => fn (string $value) : array => [
306 1
					'width' => \intval(\mb_substr($value, 6))
307 1
				]
308 3
			],
309 3
			'height=' => [
310 3
				'match' => 'start',
311 3
				'categories' => fn (string $value) : array => [
312 1
					'height' => \intval(\mb_substr($value, 7))
313 1
				]
314 3
			],
315 3
			'dpi=' => [
316 3
				'match' => 'start',
317 3
				'categories' => fn (string $value) : array => [
318
					'dpi' => \mb_substr($value, 4)
319
				]
320 3
			],
321 3
			'FBSN/' => [
322 3
				'match' => 'start',
323 3
				'categories' => fn (string $value) : array => [
324 2
					'platform' => \mb_substr($value, 5)
325 2
				]
326 3
			],
327 3
			'FBSV' => [
328 3
				'match' => 'start',
329 3
				'categories' => fn (string $value) : array => [
330 2
					'platformversion' => \mb_substr($value, 5)
331 2
				]
332 3
			],
333 3
			'isDarkMode/' => [
334 3
				'match' => 'start',
335 3
				'categories' => function (string $value) : array {
336 1
					$mode = \mb_substr($value, 11);
337 1
					return [
338 1
						'darkmode' => \in_array($mode, ['0', '1'], true) ? \boolval($mode) : null
339 1
					];
340 3
				}
341 3
			],
342 3
			'ByteFullLocale/' => [
343 3
				'match' => 'start',
344 3
				'categories' => $fn['langslash']
345 3
			],
346 3
			'NetType/' => [
347 3
				'match' => 'start',
348 3
				'categories' => fn (string $value) : array => [
349 2
					'nettype' => \mb_convert_case(\mb_substr($value, 8), MB_CASE_UPPER)
350 2
				]
351 3
			],
352
353
			// other
354 3
			'MAUI' => [
355 3
				'match' => 'start',
356 3
				'categories' => fn (string $value) : array => [
357 1
					'type' => 'human',
358 1
					'app' => $value
359 1
				]
360 3
			],
361
362
			// TikTok
363 3
			'AppName/' => [
364 3
				'match' => 'start',
365 3
				'categories' => fn(string $value) : array => [
366 2
					'app' => $value === 'AppName/musical_ly' ? 'TikTok' : \mb_substr($value, 8)
367 2
				]
368 3
			],
369 3
			'app_version/' => [
370 3
				'match' => 'start',
371 3
				'categories' => fn(string $value) : array => [
372 2
					'appversion' => \mb_substr($value, 12)
373 2
				]
374 3
			],
375 3
			'AppVersion/' => [
376 3
				'match' => 'any',
377 3
				'categories' => fn(string $value) : array => [
378 1
					'appversion' => \explode('/', $value, 2)[1]
379 1
				]
380 3
			],
381 3
			'musical_ly' => [
382 3
				'match' => 'start',
383 3
				'categories' => fn(string $value) : array => [
384 1
					'app' => 'TikTok',
385 1
					'appversion' => \str_replace('_', '.', \mb_substr(\explode(' ', $value, 2)[0], 11))
386 1
				]
387 3
			],
388
				
389
			// generic
390 3
			'App' => [
391 3
				'match' => 'any',
392 3
				'categories' => $fn['appslash']
393 3
			],
394 3
		];
395
	}
396
}