Passed
Push — main ( 0a2d45...0009be )
by Will
02:48
created

apps::get()   F

Complexity

Conditions 34
Paths 1

Size

Total Lines 356
Code Lines 254

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 327
CRAP Score 34.0222

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 254
c 1
b 0
f 0
dl 0
loc 356
ccs 327
cts 336
cp 0.9732
rs 3.3333
cc 34
nc 1
nop 0
crap 34.0222

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
/**
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 43
	public static function get() : array {
16 1
		$fn = [
17 1
			'appslash' => function (string $value, int $i, array $tokens, string $match) : ?array {
18 43
				if (\mb_stripos($value, 'AppleWebKit') !== 0 && !\str_contains($value, '://')) {
19 18
					$parts = \explode('/', $value, 4);
20 18
					$offset = isset($parts[2]) ? 1 : 0;
21 18
					$map = [
22 18
						'YaApp_iOS' => 'Yandex',
23 18
						'YaApp_Android' => 'Yandex',
24 18
						'YaSearchApp' => 'Yandex',
25 18
						'YaBrowser' => 'Yandex',
26 18
						'LinkedInApp' => 'LinkedIn',
27 18
						'[LinkedInApp]' => 'LinkedIn',
28 18
						'GoogleApp' => 'Google',
29 18
						'com.zhiliaoapp.musically' => 'TikTok',
30 18
						'com.google.android.apps.searchlite' => 'Google (Lite)',
31 18
						'com.google.photos' => 'Google Photos',
32 18
						'com.google.ios.youtube' => 'YouTube',
33 18
						'com.google.GoogleMobile' => 'Google',
34 18
						'AlohaBrowserApp' => 'Aloha'
35 18
					];
36 18
					$app = $parts[0 + $offset];
37 18
					if (\mb_stripos($app, \rtrim($match, '/')) !== false) { // check the match is before the slash
38 18
						return [
39 18
							'type' => 'human',
40 18
							'app' => $map[$app] ?? $app,
41 18
							'appversion' => $parts[1 + $offset] ?? null
42 18
						];
43
					}
44
				}
45 38
				return null;
46 1
			},
47 1
			'langslash' => function (string $value) : array {
48 6
				$parts = \explode('-', \str_replace('_', '-', \explode('/', $value, 2)[1]), 4);
49 6
				$suffix = $parts[2] ?? $parts[1] ?? null;
50 6
				return [
51 6
					'language' => \strtolower($parts[0]).($suffix !== null ? '-'.\strtoupper($suffix) : '')
52 6
				];
53 1
			}
54 1
		];
55 1
		return [
56 1
			'OcIdWebView' => [
57 1
				'match' => 'exact',
58 1
				'categories' => function (string $value, int $i, array $tokens) : array {
59 1
					$data = [
60 1
						'app' => $value
61 1
					];
62 1
					if (!empty($tokens[$i+1]) && ($json = \json_decode($tokens[$i+1], true)) !== null) {
63 1
						$data['appversion'] = $json['appVersion'] ?? null;
64 1
						$data['darkmode'] = isset($json['isDarkTheme']) ? \boolval($json['isDarkTheme']) : null;
65
					}
66 1
					return $data;
67 1
				}
68 1
			],
69 1
			'com.google.GoogleMobile/' => [
70 1
				'match' => 'start',
71 1
				'categories' => function (string $value, int $i, array $tokens, string $match) use ($fn) : array {
72
					return \array_merge($fn['appslash']($value, $i, $tokens, $match), [
73
						'category' => 'mobile'
74
					]);
75 1
				}
76 1
			],
77 1
			'com.google.' => [
78 1
				'match' => 'start',
79 1
				'categories' => $fn['appslash']
80 1
			],
81 1
			'Instagram' => [
82 1
				'match' => 'any',
83 1
				'categories' => function (string $value, int $i, array $tokens) : array {
84 6
					$parts = \explode(' ', $value, 4);
85 6
					$data = [
86 6
						'type' => 'human',
87 6
						'app' => 'Instagram',
88 6
						'appversion' => $parts[1] ?? null,
89 6
						'platform' => empty($parts[2]) ? null : platforms::getPlatform($parts[2])
90 6
					];
91 6
					foreach (\array_slice($tokens, $i + 1) AS $key => $item) {
92 6
						if (($ipados = \str_starts_with($item, 'iPadOS')) || \str_starts_with($item, 'iOS ')) {
93 2
							$data['kernel'] = 'Linux';
94 2
							$data['platform'] = 'iOS';
95 2
							$data['platformversion'] = \str_replace('_', '.', \mb_substr($item, $ipados ? 7 : 4));
96 2
							$data['density'] = \floatval(\mb_substr($item, 6));
97 6
						} elseif (($iphone = \str_starts_with($item, 'iPhone')) || ($ipad = \str_starts_with($item, 'iPad')) || \str_starts_with($item, 'iPod')) {
98 2
							$data['vendor'] = 'Apple';
99 2
							$data['category'] = empty($ipad) ? 'mobile' : 'tablet';
100 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...
101 2
							$data['model'] = \str_replace(',', '.', \mb_substr($item, $iphone ? 6 : 4));
102 2
							$data['architecture'] = 'arm';
103 2
							$data['bits'] = 64;
104 6
						} elseif (\str_starts_with($item, 'scale=')) {
105 2
							$data['density'] = \floatval(\mb_substr($item, 6));
106 6
						} elseif (\str_ends_with($item, 'dpi')) {
107 5
							$data['dpi'] = \intval(\mb_substr($item, 0, -3));
108 6
						} elseif (\str_contains($item, 'x') && \strspn($item, '0123456789x') === \strlen($item)) {
109 6
							list($data['width'], $data['height']) = \array_map('intval', \explode('x', $item, 2));
110
111
							// get device when the UA string starts with "Instagram"
112 6
							if ($i === 0 && !isset($data['vendor'])) {
113 1
								$device = [
114 1
									\trim(\mb_strstr($tokens[$key + 2] ?? '', '/') ?: $tokens[$key + 2] ?? '', '/ '), // sometimes the vendor name has a / with the correct name after
115 1
									$tokens[$key + 3] ?? null
116 1
								];
117 1
								$data = \array_merge($data, devices::getDevice(\implode(' ', \array_filter($device))));
118 1
								break;
119
							}
120
						}
121
					}
122 6
					return $data;
123 1
				}
124 1
			],
125 1
			'GSA/' => [
126 1
				'match' => 'any',
127 1
				'categories' => fn (string $value) : array => [
128 3
					'app' => 'Google',
129 3
					'appversion' => \mb_substr($value, 4)
130 3
				]
131 1
			],
132 1
			'DuckDuckGo/' => [
133 1
				'match' => 'start',
134 1
				'categories' => $fn['appslash']
135 1
			],
136 1
			'FlipboardProxy/' => [
137 1
				'match' => 'start',
138 1
				'categories' => $fn['appslash']
139 1
			],
140 1
			'Emacs/' => [
141 1
				'match' => 'start',
142 1
				'categories' => $fn['appslash']
143 1
			],
144 1
			'AndroidDownloadManager/' => [
145 1
				'match' => 'start',
146 1
				'categories' => $fn['appslash']
147 1
			],
148 1
			'Google-Read-Aloud' => [
149 1
				'match' => 'exact',
150 1
				'categories' => [
151 1
					'type' => 'human',
152 1
					'app' => 'Google-Read-Aloud'
153 1
				]
154 1
			],
155 1
			'Zoom ' => [
156 1
				'match' => 'start',
157 1
				'categories' => fn (string $value) : array => [
158 1
					'app' => 'Zoom',
159 1
					'appversion' => \mb_substr($value, 5)
160 1
				]
161 1
			],
162 1
			'OculusBrowser/' => [
163 1
				'match' => 'start',
164 1
				'categories' => $fn['appslash']
165 1
			],
166 1
			'YaBrowser/' => [
167 1
				'match' => 'start',
168 1
				'categories' => $fn['appslash']
169 1
			],
170 1
			'choqok/' => [
171 1
				'match' => 'start',
172 1
				'categories' => $fn['appslash']
173 1
			],
174 1
			'PowerShell/' => [
175 1
				'match' => 'start',
176 1
				'categories' => $fn['appslash']
177 1
			],
178 1
			'Quora ' => [
179 1
				'match' => 'start',
180 1
				'categories' => fn (string $value) : array => [
181
					'type' => 'human',
182
					'app' => 'Quora',
183
					'appversion' => \explode(' ', $value, 3)[1]
184
				]
185 1
			],
186
187
			// special parser for Facebook app because it is completely different to any other
188 1
			'FBAN/' => [
189 1
				'match' => 'any',
190 1
				'categories' => function (string $value) : array {
191 4
					$map = [
192 4
						'FBAN/MessengerLiteForiOS' => [
193 4
							'type' => 'human',
194 4
							'app' => 'Facebook Messenger',
195 4
							'platform' => 'iOS'
196 4
						],
197 4
						'FBAN/FB4A' => [
198 4
							'type' => 'human',
199 4
							'app' => 'Facebook',
200 4
							'platform' => 'Android'
201 4
						],
202 4
						'FBAN/FBIOS' => [
203 4
							'type' => 'human',
204 4
							'app' => 'Facebook',
205 4
							'platform' => 'iOS'
206 4
						],
207 4
						'FBAN/FB4FireTV' => [
208 4
							'type' => 'human',
209 4
							'category' => 'tv',
210 4
							'app' => 'Facebook',
211 4
							'platform' => 'Android'
212 4
						],
213 4
						'FBAN/MessengerDesktop' => [
214 4
							'type' => 'human',
215 4
							'category' => 'desktop',
216 4
							'app' => 'Facebook Messenger'
217 4
						],
218 4
						'FacebookCanvasDesktop FBAN/GamesWindowsDesktopApp' => [
219 4
							'type' => 'human',
220 4
							'platform' => 'Windows',
221 4
							'category' => 'desktop',
222 4
							'app' => 'Facebook Gamesroom'
223 4
						]
224 4
					];
225 4
					return $map[$value] ?? [
226 4
						'app' => 'Facebook',
227 4
						'type' => 'human'
228
					];
229 1
				}
230 1
			],
231 1
			'FB_IAB/' => [
232 1
				'match' => 'start',
233 1
				'categories' => [
234 1
					'app' => 'Facebook'
235 1
				]
236 1
			],
237 1
			'FBAV/' => [
238 1
				'match' => 'start',
239 1
				'categories' => fn (string $value) : array => [
240 8
					'appversion' => \mb_substr($value, 5)
241 8
				]
242 1
			],
243 1
			'FBMF/' => [
244 1
				'match' => 'start',
245 1
				'categories' => fn (string $value) : array => [
246 1
					'vendor' => devices::getVendor(\mb_substr($value, 5))
247 1
				]
248 1
			],
249 1
			'FBDV/' => [
250 1
				'match' => 'start',
251 1
				'categories' => fn (string $value) : array => [
252 2
					'device' => \mb_substr($value, 5)
253 2
				]
254 1
			],
255 1
			'FBMD/' => [
256 1
				'match' => 'start',
257 1
				'categories' => fn (string $value) : array => [
258 2
					'model' => \mb_substr($value, 5)
259 2
				]
260 1
			],
261 1
			'FBLC/' => [
262 1
				'match' => 'start',
263 1
				'categories' => $fn['langslash']
264 1
			],
265 1
			'FBDM/' => [
266 1
				'match' => 'start',
267 1
				'categories' => function (string $value) : array {
268 1
					$data = [];
269 1
					foreach (\explode(',', \trim(\mb_substr($value, 5), '{}')) AS $item) {
270 1
						$parts = \explode('=', $item);
271 1
						if (!empty($parts[1])) {
272 1
							if (\is_numeric($parts[1])) {
273 1
								$parts[1] = \str_contains($parts[1], '.') ? \floatval($parts[1]) : \intval($parts[1]);
274
							}
275 1
							$data[$parts[0]] = $parts[1];
276
						}
277
					}
278 1
					return $data;
279 1
				}
280 1
			],
281 1
			'width=' => [
282 1
				'match' => 'start',
283 1
				'categories' => fn (string $value) : array => [
284 1
					'width' => \intval(\mb_substr($value, 6))
285 1
				]
286 1
			],
287 1
			'height=' => [
288 1
				'match' => 'start',
289 1
				'categories' => fn (string $value) : array => [
290 1
					'height' => \intval(\mb_substr($value, 7))
291 1
				]
292 1
			],
293 1
			'dpi=' => [
294 1
				'match' => 'start',
295 1
				'categories' => fn (string $value) : array => [
296
					'dpi' => \mb_substr($value, 4)
297
				]
298 1
			],
299 1
			'FBSN/' => [
300 1
				'match' => 'start',
301 1
				'categories' => fn (string $value) : array => [
302 2
					'platform' => \mb_substr($value, 5)
303 2
				]
304 1
			],
305 1
			'FBSV' => [
306 1
				'match' => 'start',
307 1
				'categories' => fn (string $value) : array => [
308 2
					'platformversion' => \mb_substr($value, 5)
309 2
				]
310 1
			],
311 1
			'isDarkMode/' => [
312 1
				'match' => 'start',
313 1
				'categories' => function (string $value) : array {
314 1
					$mode = \mb_substr($value, 11);
315 1
					return [
316 1
						'darkmode' => \in_array($mode, ['0', '1'], true) ? \boolval($mode) : null
317 1
					];
318 1
				}
319 1
			],
320 1
			'ByteFullLocale/' => [
321 1
				'match' => 'start',
322 1
				'categories' => $fn['langslash']
323 1
			],
324 1
			'NetType/' => [
325 1
				'match' => 'start',
326 1
				'categories' => fn (string $value) : array => [
327 2
					'nettype' => \mb_convert_case(\mb_substr($value, 8), MB_CASE_UPPER)
328 2
				]
329 1
			],
330
331
			// other
332 1
			'MAUI' => [
333 1
				'match' => 'start',
334 1
				'categories' => fn (string $value) : array => [
335 1
					'type' => 'human',
336 1
					'app' => $value
337 1
				]
338 1
			],
339
340
			// TikTok
341 1
			'AppName/' => [
342 1
				'match' => 'start',
343 1
				'categories' => fn(string $value) : array => [
344 2
					'app' => $value === 'AppName/musical_ly' ? 'TikTok' : \mb_substr($value, 8)
345 2
				]
346 1
			],
347 1
			'app_version/' => [
348 1
				'match' => 'start',
349 1
				'categories' => fn(string $value) : array => [
350 2
					'appversion' => \mb_substr($value, 12)
351 2
				]
352 1
			],
353 1
			'AppVersion/' => [
354 1
				'match' => 'any',
355 1
				'categories' => fn(string $value) : array => [
356 1
					'appversion' => \explode('/', $value, 2)[1]
357 1
				]
358 1
			],
359 1
			'musical_ly' => [
360 1
				'match' => 'start',
361 1
				'categories' => fn(string $value) : array => [
362 1
					'app' => 'TikTok',
363 1
					'appversion' => \str_replace('_', '.', \mb_substr(\explode(' ', $value, 2)[0], 11))
364 1
				]
365 1
			],
366
				
367
			// generic
368 1
			'App' => [
369 1
				'match' => 'any',
370 1
				'categories' => $fn['appslash']
371 1
			],
372 1
		];
373
	}
374
}