This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace UserAgentParser\Provider\Http; |
||
3 | |||
4 | use GuzzleHttp\Client; |
||
5 | use GuzzleHttp\Psr7\Request; |
||
6 | use stdClass; |
||
7 | use UserAgentParser\Exception; |
||
8 | use UserAgentParser\Model; |
||
9 | |||
10 | /** |
||
11 | * Abstraction of neutrinoapi.com |
||
12 | * |
||
13 | * @author Martin Keckeis <[email protected]> |
||
14 | * @license MIT |
||
15 | * @see https://www.neutrinoapi.com/api/user-agent-info/ |
||
16 | */ |
||
17 | class NeutrinoApiCom extends AbstractHttpProvider |
||
18 | { |
||
19 | /** |
||
20 | * Name of the provider |
||
21 | * |
||
22 | * @var string |
||
23 | */ |
||
24 | protected $name = 'NeutrinoApiCom'; |
||
25 | |||
26 | /** |
||
27 | * Homepage of the provider |
||
28 | * |
||
29 | * @var string |
||
30 | */ |
||
31 | protected $homepage = 'https://www.neutrinoapi.com/'; |
||
32 | |||
33 | protected $detectionCapabilities = [ |
||
34 | |||
35 | 'browser' => [ |
||
36 | 'name' => true, |
||
37 | 'version' => true, |
||
38 | ], |
||
39 | |||
40 | 'renderingEngine' => [ |
||
41 | 'name' => false, |
||
42 | 'version' => false, |
||
43 | ], |
||
44 | |||
45 | 'operatingSystem' => [ |
||
46 | 'name' => true, |
||
47 | 'version' => true, |
||
48 | ], |
||
49 | |||
50 | 'device' => [ |
||
51 | 'model' => true, |
||
52 | 'brand' => true, |
||
53 | 'type' => true, |
||
54 | 'isMobile' => true, |
||
55 | 'isTouch' => false, |
||
56 | ], |
||
57 | |||
58 | 'bot' => [ |
||
59 | 'isBot' => true, |
||
60 | 'name' => true, |
||
61 | 'type' => false, |
||
62 | ], |
||
63 | ]; |
||
64 | |||
65 | protected $defaultValues = [ |
||
66 | |||
67 | 'general' => [ |
||
68 | '/^unknown$/i', |
||
69 | ], |
||
70 | |||
71 | 'device' => [ |
||
72 | |||
73 | 'brand' => [ |
||
74 | '/^Generic$/i', |
||
75 | '/^generic web browser$/i', |
||
76 | ], |
||
77 | |||
78 | 'model' => [ |
||
79 | '/^Android/i', |
||
80 | '/^Windows Phone/i', |
||
81 | '/^Windows Mobile/i', |
||
82 | '/^Firefox/i', |
||
83 | '/^Generic/i', |
||
84 | '/^Tablet on Android$/i', |
||
85 | '/^Tablet$/i', |
||
86 | ], |
||
87 | ], |
||
88 | ]; |
||
89 | |||
90 | private static $uri = 'https://neutrinoapi.com/user-agent-info'; |
||
91 | |||
92 | private $apiUserId; |
||
93 | |||
94 | private $apiKey; |
||
95 | |||
96 | 22 | public function __construct(Client $client, $apiUserId, $apiKey) |
|
97 | { |
||
98 | 22 | parent::__construct($client); |
|
99 | |||
100 | 22 | $this->apiUserId = $apiUserId; |
|
101 | 22 | $this->apiKey = $apiKey; |
|
102 | 22 | } |
|
103 | |||
104 | 7 | public function getVersion() |
|
105 | { |
||
106 | 7 | return; |
|
107 | } |
||
108 | |||
109 | /** |
||
110 | * |
||
111 | * @param string $userAgent |
||
112 | * @param array $headers |
||
113 | * @return stdClass |
||
114 | * @throws Exception\RequestException |
||
115 | */ |
||
116 | 15 | protected function getResult($userAgent, array $headers) |
|
0 ignored issues
–
show
|
|||
117 | { |
||
118 | /* |
||
119 | * an empty UserAgent makes no sense |
||
120 | */ |
||
121 | 15 | if ($userAgent == '') { |
|
122 | 1 | throw new Exception\NoResultFoundException('No result found for user agent: ' . $userAgent); |
|
123 | } |
||
124 | |||
125 | $params = [ |
||
126 | 14 | 'user-id' => $this->apiUserId, |
|
127 | 14 | 'api-key' => $this->apiKey, |
|
128 | 14 | 'output-format' => 'json', |
|
129 | 14 | 'output-case' => 'snake', |
|
130 | |||
131 | 14 | 'user-agent' => $userAgent, |
|
132 | ]; |
||
133 | |||
134 | 14 | $body = http_build_query($params, null, '&'); |
|
135 | |||
136 | 14 | $request = new Request('POST', self::$uri, [ |
|
137 | 14 | 'Content-Type' => 'application/x-www-form-urlencoded', |
|
138 | ], $body); |
||
139 | |||
140 | try { |
||
141 | 14 | $response = $this->getResponse($request); |
|
142 | 2 | } catch (Exception\RequestException $ex) { |
|
143 | /* @var $prevEx \GuzzleHttp\Exception\ClientException */ |
||
144 | 2 | $prevEx = $ex->getPrevious(); |
|
145 | |||
146 | 2 | if ($prevEx->hasResponse() === true && $prevEx->getResponse()->getStatusCode() === 403) { |
|
147 | 1 | throw new Exception\InvalidCredentialsException('Your API userId "' . $this->apiUserId . '" and key "' . $this->apiKey . '" is not valid for ' . $this->getName(), null, $ex); |
|
148 | } |
||
149 | |||
150 | 1 | throw $ex; |
|
151 | } |
||
152 | |||
153 | /* |
||
154 | * no json returned? |
||
155 | */ |
||
156 | 12 | $contentType = $response->getHeader('Content-Type'); |
|
157 | 12 | if (! isset($contentType[0]) || $contentType[0] != 'application/json;charset=UTF-8') { |
|
158 | 1 | throw new Exception\RequestException('Could not get valid "application/json" response from "' . $request->getUri() . '". Response is "' . $response->getBody()->getContents() . '"'); |
|
159 | } |
||
160 | |||
161 | 11 | $content = json_decode($response->getBody()->getContents()); |
|
162 | |||
163 | /* |
||
164 | * errors |
||
165 | */ |
||
166 | 11 | if (isset($content->api_error)) { |
|
167 | 3 | switch ($content->api_error) { |
|
168 | |||
169 | 3 | case 1: |
|
170 | 1 | throw new Exception\RequestException('"' . $content->api_error_msg . '" response from "' . $request->getUri() . '". Response is "' . print_r($content, true) . '"'); |
|
171 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
172 | |||
173 | 2 | case 2: |
|
174 | 1 | throw new Exception\LimitationExceededException('Exceeded the maximum number of request with API userId "' . $this->apiUserId . '" and key "' . $this->apiKey . '" for ' . $this->getName()); |
|
175 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
176 | |||
177 | default: |
||
178 | 1 | throw new Exception\RequestException('"' . $content->api_error_msg . '" response from "' . $request->getUri() . '". Response is "' . print_r($content, true) . '"'); |
|
179 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
180 | } |
||
181 | } |
||
182 | |||
183 | /* |
||
184 | * Missing data? |
||
185 | */ |
||
186 | 8 | if (! $content instanceof stdClass) { |
|
187 | 1 | throw new Exception\RequestException('Could not get valid response from "' . $request->getUri() . '". Response is "' . $response->getBody()->getContents() . '"'); |
|
188 | } |
||
189 | |||
190 | 7 | return $content; |
|
191 | } |
||
192 | |||
193 | /** |
||
194 | * |
||
195 | * @param stdClass $resultRaw |
||
196 | * |
||
197 | * @return bool |
||
198 | */ |
||
199 | 7 | private function hasResult(stdClass $resultRaw) |
|
200 | { |
||
201 | 7 | if (isset($resultRaw->type) && $this->isRealResult($resultRaw->type)) { |
|
202 | 6 | return true; |
|
203 | } |
||
204 | |||
205 | 1 | return false; |
|
206 | } |
||
207 | |||
208 | /** |
||
209 | * |
||
210 | * @param stdClass $resultRaw |
||
211 | * @return boolean |
||
212 | */ |
||
213 | 6 | private function isBot(stdClass $resultRaw) |
|
214 | { |
||
215 | 6 | if (isset($resultRaw->type) && $resultRaw->type === 'robot') { |
|
216 | 2 | return true; |
|
217 | } |
||
218 | |||
219 | 4 | return false; |
|
220 | } |
||
221 | |||
222 | /** |
||
223 | * |
||
224 | * @param Model\Bot $bot |
||
225 | * @param stdClass $resultRaw |
||
226 | */ |
||
227 | 2 | private function hydrateBot(Model\Bot $bot, stdClass $resultRaw) |
|
228 | { |
||
229 | 2 | $bot->setIsBot(true); |
|
230 | |||
231 | 2 | if (isset($resultRaw->browser_name)) { |
|
232 | 2 | $bot->setName($this->getRealResult($resultRaw->browser_name)); |
|
233 | } |
||
234 | 2 | } |
|
235 | |||
236 | /** |
||
237 | * |
||
238 | * @param Model\Browser $browser |
||
239 | * @param stdClass $resultRaw |
||
240 | */ |
||
241 | 4 | private function hydrateBrowser(Model\Browser $browser, stdClass $resultRaw) |
|
242 | { |
||
243 | 4 | if (isset($resultRaw->browser_name)) { |
|
244 | 1 | $browser->setName($this->getRealResult($resultRaw->browser_name, 'browser', 'name')); |
|
245 | } |
||
246 | |||
247 | 4 | if (isset($resultRaw->version)) { |
|
248 | 1 | $browser->getVersion()->setComplete($this->getRealResult($resultRaw->version)); |
|
249 | } |
||
250 | 4 | } |
|
251 | |||
252 | /** |
||
253 | * |
||
254 | * @param Model\OperatingSystem $os |
||
255 | * @param stdClass $resultRaw |
||
256 | */ |
||
257 | 4 | private function hydrateOperatingSystem(Model\OperatingSystem $os, stdClass $resultRaw) |
|
258 | { |
||
259 | 4 | if (isset($resultRaw->operating_system_family)) { |
|
260 | 1 | $os->setName($this->getRealResult($resultRaw->operating_system_family)); |
|
261 | } |
||
262 | |||
263 | 4 | if (isset($resultRaw->operating_system_version)) { |
|
264 | 1 | $os->getVersion()->setComplete($this->getRealResult($resultRaw->operating_system_version)); |
|
265 | } |
||
266 | 4 | } |
|
267 | |||
268 | /** |
||
269 | * |
||
270 | * @param Model\Device $device |
||
271 | * @param stdClass $resultRaw |
||
272 | */ |
||
273 | 4 | private function hydrateDevice(Model\Device $device, stdClass $resultRaw) |
|
274 | { |
||
275 | 4 | if (isset($resultRaw->mobile_model)) { |
|
276 | 2 | $device->setModel($this->getRealResult($resultRaw->mobile_model, 'device', 'model')); |
|
277 | } |
||
278 | |||
279 | 4 | if (isset($resultRaw->mobile_brand)) { |
|
280 | 2 | $device->setBrand($this->getRealResult($resultRaw->mobile_brand, 'device', 'brand')); |
|
281 | } |
||
282 | |||
283 | 4 | if (isset($resultRaw->type)) { |
|
284 | 4 | $device->setType($this->getRealResult($resultRaw->type)); |
|
285 | } |
||
286 | |||
287 | 4 | if (isset($resultRaw->is_mobile) && $resultRaw->is_mobile === true) { |
|
288 | 1 | $device->setIsMobile(true); |
|
289 | } |
||
290 | 4 | } |
|
291 | |||
292 | 15 | public function parse($userAgent, array $headers = []) |
|
293 | { |
||
294 | 15 | $resultRaw = $this->getResult($userAgent, $headers); |
|
295 | |||
296 | /* |
||
297 | * No result found? |
||
298 | */ |
||
299 | 7 | if ($this->hasResult($resultRaw) !== true) { |
|
300 | 1 | throw new Exception\NoResultFoundException('No result found for user agent: ' . $userAgent); |
|
301 | } |
||
302 | |||
303 | /* |
||
304 | * Hydrate the model |
||
305 | */ |
||
306 | 6 | $result = new Model\UserAgent($this->getName(), $this->getVersion()); |
|
307 | 6 | $result->setProviderResultRaw($resultRaw); |
|
308 | |||
309 | /* |
||
310 | * Bot detection |
||
311 | */ |
||
312 | 6 | if ($this->isBot($resultRaw) === true) { |
|
313 | 2 | $this->hydrateBot($result->getBot(), $resultRaw); |
|
314 | |||
315 | 2 | return $result; |
|
316 | } |
||
317 | |||
318 | /* |
||
319 | * hydrate the result |
||
320 | */ |
||
321 | 4 | $this->hydrateBrowser($result->getBrowser(), $resultRaw); |
|
322 | 4 | $this->hydrateOperatingSystem($result->getOperatingSystem(), $resultRaw); |
|
323 | 4 | $this->hydrateDevice($result->getDevice(), $resultRaw); |
|
324 | |||
325 | 4 | return $result; |
|
326 | } |
||
327 | } |
||
328 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.