browsers   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 243
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 203
dl 0
loc 243
ccs 228
cts 228
cp 1
rs 10
c 2
b 0
f 0
wmc 19

2 Methods

Rating   Name   Duplication   Size   Complexity  
B getBrowser() 0 54 6
C get() 0 180 13
1
<?php
2
declare(strict_types = 1);
3
namespace hexydec\agentzero;
4
5
class browsers {
6
7 88
	protected static function getBrowser(string $value, int $i, array $tokens, string $key, array $config = []) : array {
8 88
		if (!\str_contains($value, 'Opera Mini') && ($browser = \mb_strrchr($value, ' ')) !== false) {
9 2
			$value = \ltrim($browser);
10
		}
11 88
		$parts = \explode('/', $value); // split more incase there are more slashes
12 88
		$map = [
13 88
			'opr' => 'Opera',
14 88
			'crios' => 'Chrome',
15 88
			'edg' => 'Edge',
16 88
			'edgios' => 'Edge',
17 88
			'fxios' => 'Firefox',
18 88
			'edga' => 'Edge',
19 88
			'webpositive' => 'WebPositive',
20 88
			'nintendobrowser' => 'NintendoBrowser',
21 88
			'up.browser' => 'UP.Browser',
22 88
			'ucbrowser' => 'UCBrowser',
23 88
			'netfront' => 'NetFront',
24 88
			'seamonkey' => 'SeaMonkey',
25 88
			'icecat' => 'IceCat',
26 88
			'iceape' => 'IceApe',
27 88
			'iceweasel' => 'IceWeasel',
28 88
			'bonecho' => 'BonEcho',
29 88
			'palemoon' => 'PaleMoon',
30 88
			'k-meleon' => 'K-Meleon',
31 88
			'samsungbrowser' => 'Samsung Internet',
32 88
			'huaweibrowser' => 'Huawei Browser',
33 88
			'qqbrowser' => 'QQ Browser',
34 88
			'miuibrowser' => 'MIUI Browser',
35 88
			'vivobrowser' => 'Vivo Browser',
36 88
			'android-com.vivo.browser' => 'Vivo Browser'
37 88
		];
38 88
		$data = ['type' => 'human'];
39 88
		$browser = \mb_strtolower(\array_shift($parts));
40 88
		$data['browser'] = $map[$browser] ?? \mb_convert_case($browser, MB_CASE_TITLE);
41
42
		// get browser version
43 88
		foreach ($parts AS $item) {
44 88
			if (\strpbrk($item, '1234567890') !== false) {
45 88
				$data['browserversion'] = $item;
46 88
				break;
47
			}
48
		}
49 88
		$map = [
50 88
			'Samsung Internet' => 'samsung',
51 88
			'Huawei Browser' => 'huawei',
52 88
			'K-Meleon' => 'kmeleon',
53 88
			'Fennec' => 'firefox',
54 88
			'Native Opera Mini' => 'opera',
55 88
			'Cronet' => 'chrome'
56 88
		];
57 88
		$key = $map[$data['browser']] ?? \mb_strtolower($data['browser']);
58 88
		return \array_merge(
59 88
			$data,
60 88
			isset($data['browserversion']) ? versions::get($key, $data['browserversion'], $config) : []
61 88
		);
62
	}
63
	/**
64
	 * Generates a configuration array for matching browsers
65
	 * 
66
	 * @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
67
	 */
68 63
	public static function get() : array {
69 49
		$fn = [
70 49
			'browserslash' => fn (string $value, int $i, array $tokens, string $key, array $config = []) : array => self::getBrowser($value, $i, $tokens, $key, $config),
71 49
			'gecko' => function (string $value, int $i, array $tokens, string $key, array $config = []) : array {
72 27
				$parts = \explode('/', $value, 2);
73 27
				return \array_replace(self::getBrowser($value, $i, $tokens, $key, $config), [
74 27
					'engine' => 'Gecko',
75 27
					'engineversion' => $parts[1] ?? null,
76 27
				]);
77 49
			},
78 49
			'presto' => function (string $value, int $i, array $tokens, string $key, array $config = []) : array {
79 5
				$parts = \explode('/', $value, 2);
80 5
				return \array_replace(self::getBrowser($value, $i, $tokens, $key, $config), [
81 5
					'engine' => 'Presto',
82 5
					'engineversion' => $parts[1] ?? null,
83 5
				]);
84 49
			},
85 49
			'chromium' => function (string $value, int $i, array $tokens, string $key, array $config = []) : array {
86 63
				$parts = \explode('/', $value, 3);
87 63
				$engineversion = isset($parts[1]) && \strspn($parts[1], '1234567890.') === \strlen($parts[1]) ? $parts[1] : null;
88 63
				return \array_replace(self::getBrowser($value, $i, $tokens, $key, $config), [
89 63
					'engine' => \intval($engineversion ?? 28) < 28 ? 'WebKit' : 'Blink',
90 63
					'engineversion' => $engineversion
91 63
				]);
92 49
			},
93 49
			'safari' => function (string $value, int $i, array $tokens, string $key, array $config = []) : array {
94 35
				$parts = \explode('/', $value, 2);
95 35
				$version = $parts[1] ?? null;
96 35
				foreach ($tokens AS $item) {
97 35
					if (\mb_stripos($item, 'Version/') === 0) {
98 23
						$version = \mb_substr($item, 8);
99
					}
100
				}
101 35
				return \array_replace([
102 35
					'type' => 'human',
103 35
					'browser' => 'Safari',
104 35
					'browserversion' => $version ?? null,
105 35
					'engine' => 'WebKit',
106 35
					'engineversion' => $parts[1] ?? null
107 35
				], $version !== null ? versions::get('safari', $version, $config) : []);
108 49
			},
109 49
		];
110 17
		return [
111 17
			'Opera Mini/' => new props('start', $fn['presto']),
112 17
			'Native Opera Mini/' => new props('start', $fn['presto']),
113 17
			'Opera/' => new props('start', $fn['presto']),
114 17
			'OPR/' => new props('start', $fn['browserslash']),
115 17
			'CriOS/' => new props('start', $fn['browserslash']),
116 17
			'Brave/' => new props('start', $fn['browserslash']),
117 17
			'Vivaldi/' => new props('start', $fn['browserslash']),
118 17
			'Maxthon/' => new props('start', $fn['browserslash']),
119 17
			'Maxthon ' => new props('start', fn (string $value, int $i, array $tokens, string $key, array $config = []) : array => \array_merge([
120 17
				'browser' => 'Maxthon',
121 17
				'browserversion' => \mb_substr($value, 8)
122 17
			], versions::get('maxathon', \mb_substr($value, 8), $config))),
123 17
			'Konqueror/' => new props('start', $fn['browserslash']),
124 17
			'K-Meleon/' => new props('start', $fn['browserslash']),
125 17
			'UCBrowser/' => new props('start', $fn['browserslash']),
126 17
			'Waterfox/' => new props('start', $fn['browserslash']),
127 17
			'PaleMoon/' => new props('start', $fn['browserslash']),
128 17
			'IceWeasel/' => new props('start', $fn['browserslash']),
129 17
			'IceCat/' => new props('start', $fn['browserslash']),
130 17
			'IceApe/' => new props('start', $fn['browserslash']),
131 17
			'Basilisk/' => new props('start', $fn['browserslash']),
132 17
			'SeaMonkey/' => new props('start', $fn['browserslash']),
133 17
			'UP.Browser/' => new props('start', $fn['browserslash']),
134 17
			'Netscape/' => new props('start', $fn['browserslash']),
135 17
			'Thunderbird/' => new props('start', $fn['browserslash']),
136 17
			'Galeon/' => new props('start', $fn['browserslash']),
137 17
			'WebPositive/' => new props('start', $fn['browserslash']),
138 17
			'K-Ninja/' => new props('start', $fn['browserslash']),
139 17
			'SamsungBrowser/' => new props('start', $fn['browserslash']),
140 17
			'HuaweiBrowser/' => new props('start', $fn['browserslash']),
141 17
			'NintendoBrowser/' => new props('start', $fn['browserslash']),
142 17
			'Epiphany/' => new props('start', $fn['browserslash']),
143 17
			'Silk/' => new props('start', $fn['browserslash']),
144 17
			'NetFront/' => new props('start', $fn['browserslash']),
145 17
			'Dooble/' => new props('start', $fn['browserslash']),
146 17
			'Falkon/' => new props('start', $fn['browserslash']),
147 17
			'Namoroka/' => new props('start', $fn['browserslash']),
148 17
			'CocCoc/' => new props('start', $fn['browserslash']),
149 17
			'Obigo/' => new props('start', $fn['browserslash']),
150 17
			'VivoBrowser/' => new props('start', $fn['browserslash']),
151 17
			'com.vivo.browser/' => new props('any', $fn['browserslash']),
152 17
			'QQBrowser/' => new props('any', function (string $value, int $i, array $tokens, string $key, array $config = []) use ($fn) : array {
153 2
				return $fn['browserslash'](\mb_substr($value, \mb_stripos($value, 'QQBrowser/') ?: 0), $i, $tokens, $key, $config); // sometimes missing a space from previous declaration, and MQQBrowser for mobile.
154 17
			}),
155 17
			'MiuiBrowser/' => new props('any', function (string $value, int $i, array $tokens, string $key, array $config = []) use ($fn) : array {
156 2
				return $fn['browserslash'](\mb_substr($value, \mb_stripos($value, 'MiuiBrowser/') ?: 0), $i, $tokens, $key, $config);
157 17
			}),
158 17
			'Lynx/' => new props('start', fn (string $value) : array => [
159 2
				'browser' => 'Lynx',
160 2
				'browserversion' => \explode('/', $value, 2)[1] ?? null,
161 2
				'engine' => 'Libwww',
162 2
				'type' => 'human',
163 2
				'category' => 'desktop'
164 2
			]),
165 17
			'Midori' => new props('start', function (string $value, int $i, array $tokens, string $key, array $config = []) : array {
166 1
				$parts = \explode('/', $value, 2);
167 1
				$version = $parts[1] ?? \explode(' ', $value, 2)[1] ?? null;
168 1
				$major = $version !== null ? \intval($version) : null;
169 1
				return \array_merge([
170 1
					'type' => 'human',
171 1
					'browser' => 'Midori',
172 1
					'engine' => $major >= 11 ? 'Gecko' : ($major < 9 ? 'WebKit' : 'Blink'),
173 1
					'browserversion' => $version
174 1
				], $version !== null ? versions::get('midori', $version, $config) : []);
175 17
			}),
176 17
			'PrivacyBrowser/' => new props('start', $fn['browserslash']),
177 17
			'Fennec/' => new props('start', $fn['gecko']),
178 17
			'Firefox/' => new props('start', $fn['gecko']),
179 17
			' Firefox/' => new props('any', $fn['gecko']),
180 17
			'Firefox' => new props('exact', [
181 17
				'type' => 'human',
182 17
				'engine' => 'Gecko',
183 17
				'browser' => 'Firefox'
184 17
			]),
185 17
			'Minimo/' => new props('start', function (string $value, int $i, array $tokens, string $key, array $config = []) use ($fn) : array {
186 1
				$data = $fn['browserslash']($value, $i, $tokens, $key, $config);
187 1
				return \array_merge($data, [
188 1
					'engine' => 'Gecko'
189 1
				]);
190 17
			}),
191 17
			'BonEcho/' => new props('start', function (string $value, int $i, array $tokens, string $key, array $config = []) use ($fn) : array {
192 1
				$data = $fn['browserslash']($value, $i, $tokens, $key, $config);
193 1
				return \array_merge($data, [
194 1
					'engine' => 'Gecko'
195 1
				]);
196 17
			}),
197 17
			'Links/' => new props('start', $fn['browserslash']),
198 17
			'Links' => new props('exact', fn (string $value, int $i, array $tokens, string $key, array $config = []) => [
199 2
				'type' => 'human',
200 2
				'browser' => $value,
201 2
				'browserversion' => $tokens[$i + 1]
202 2
			]),
203 17
			'Elinks/' => new props('start', $fn['browserslash']),
204 17
			'ELinks' => new props('exact', fn (string $value, int $i, array $tokens, string $key, array $config = []) => [
205 2
				'type' => 'human',
206 2
				'browser' => $value,
207 2
				'browserversion' => $tokens[$i + 1]
208 2
			]),
209 17
			'Blazer' => new props('start', fn (string $value, int $i, array $tokens, string $key, array $config = []) : array => [
210 3
				'type' => 'human',
211 3
				'browser' => 'Blazer',
212 3
				'browserversion' => \mb_substr($value, 7),
213 3
				'engine' => 'Proprietary'
214 3
			]),
215 17
			'Edg/' => new props('start', $fn['browserslash']),
216 17
			'EdgA/' => new props('start', $fn['browserslash']),
217 17
			'Edge/' => new props('start', $fn['browserslash']),
218 17
			'EdgiOS/' => new props('start', $fn['browserslash']),
219 17
			'FxiOS/' => new props('start', $fn['browserslash']),
220 17
			'MSIE ' => new props('start', fn (string $value, int $i, array $tokens, string $key, array $config = []) : array => \array_merge([
221 17
				'type' => 'human',
222 17
				'browser' => 'Internet Explorer',
223 17
				'browserversion' => \mb_substr($value, 5),
224 17
				'engine' => 'Trident'
225 17
			], versions::get('ie', \mb_substr($value, 5), $config))),
226 17
			'BOIE9' => new props('start', fn (string $value, int $i, array $tokens, string $key, array $config = []) => \array_merge([
227 17
				'type' => 'human',
228 17
				'browser' => 'Internet Explorer',
229 17
				'browserversion' => '9.0',
230 17
				'engine' => 'Trident'
231 17
			], versions::get('ie', '9.0', $config))),
232 17
			'IEMobile/' => new props('start', fn (string $value, int $i, array $tokens, string $key, array $config = []) : array => \array_merge([
233 17
				'type' => 'human',
234 17
				'browser' => 'Internet Explorer',
235 17
				'browserversion' => \mb_substr($value, 9),
236 17
				'engine' => 'Trident'
237 17
			], versions::get('ie', \mb_substr($value, 9), $config))),
238 17
			'Trident' => new props('start', [ // infill for missing browser name
239 17
				'browser' => 'Internet Explorer'
240 17
			]),
241 17
			'Cronet/' => new props('start', $fn['chromium']),
242 17
			'Chromium/' => new props('start', $fn['chromium']),
243 17
			'Chrome/' => new props('any', $fn['chromium']),
244 17
			'Safari/' => new props('start', $fn['safari']),
245 17
			'Mozilla/' => new props('start', $fn['browserslash']),
246 17
			'rv:' => new props('start', fn (string $value) : array => [
247 38
				'browserversion' => \mb_substr($value, 3)
248 38
			])
249 17
		];
250
	}
251
}