1<?php
2
3/**
4 * Device Detector - The Universal Device Detection library for parsing User Agents
5 *
6 * @link https://matomo.org
7 *
8 * @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later
9 */
10
11declare(strict_types=1);
12
13namespace DeviceDetector\Parser\Client\Browser\Engine;
14
15use DeviceDetector\Parser\Client\AbstractClientParser;
16
17/**
18 * Class Version
19 *
20 * Client parser for browser engine version detection
21 */
22class Version extends AbstractClientParser
23{
24    /**
25     * @var string
26     */
27    private $engine;
28
29    /**
30     * Version constructor.
31     *
32     * @param string $ua
33     * @param string $engine
34     */
35    public function __construct(string $ua, string $engine)
36    {
37        parent::__construct($ua);
38
39        $this->engine = $engine;
40    }
41
42    /**
43     * @inheritdoc
44     */
45    public function parse(): ?array
46    {
47        if (empty($this->engine)) {
48            return null;
49        }
50
51        if ('Gecko' === $this->engine || 'Clecko' === $this->engine) {
52            $pattern = '~[ ](?:rv[: ]([0-9.]+)).*(?:g|cl)ecko/[0-9]{8,10}~i';
53
54            if (\preg_match($pattern, $this->userAgent, $matches)) {
55                return ['version' => \array_pop($matches)];
56            }
57        }
58
59        $engineToken = $this->engine;
60
61        if ('Blink' === $this->engine) {
62            $engineToken = 'Chr[o0]me|Chromium|Cronet';
63        }
64
65        if ('Arachne' === $this->engine) {
66            $engineToken = 'Arachne\/5\.';
67        }
68
69        if ('LibWeb' === $this->engine) {
70            $engineToken = 'LibWeb\+LibJs';
71        }
72
73        \preg_match(
74            "~(?:{$engineToken})\s*[/_]?\s*((?(?=\d+\.\d)\d+[.\d]*|\d{1,7}(?=(?:\D|$))))~i",
75            $this->userAgent,
76            $matches
77        );
78
79        if (!$matches) {
80            return null;
81        }
82
83        return ['version' => \array_pop($matches)];
84    }
85}
86