Completed
Branch 3.0.0 (5cf6f2)
by Serhii
03:37 queued 39s
created

Detector::getWindowsVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 10
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 14
rs 9.4285
1
<?php
2
/**
3
 * @author Sergey Nehaenko <[email protected]>
4
 * @license GPL
5
 * @copyright Sergey Nehaenko &copy 2016
6
 * @version 3.0.0
7
 * @project browser-detector
8
 */
9
10
namespace EndorphinStudio\Detector;
11
12
class Detector
13
{
14
    /**
15
     * @return string Path to directory with xml data files
16
     */
17
    public function getPathToData()
18
    {
19
        return $this->PathToData;
20
    }
21
22
    /**
23
     * @return array Xml data object
24
     */
25
    public function getXmlData()
26
    {
27
        return $this->xmlData;
28
    }
29
30
    /**
31
     * @param string $PathToData
32
     */
33
    public function setPathToData($PathToData)
34
    {
35
        $this->PathToData = $PathToData;
36
    }
37
38
    /**
39
     * @param array $xmlData Xml data object
40
     */
41
    public function setXmlData($xmlData)
42
    {
43
        $this->xmlData = $xmlData;
44
    }
45
    /** @var  string Path to directory with xml data */
46
    private $PathToData;
47
48
    /** @var array Xml Data */
49
    private $xmlData;
50
51
    /**
52
     * Detector constructor.
53
     * @param string $pathToData Path to directory with xml data files
54
     */
55
    private function __construct($pathToData='auto')
56
    {
57
        if($pathToData == 'auto')
58
        {
59
            $this->setPathToData(str_replace('src','data',__DIR__).'/');
60
        }
61
62
        $xml = array('Robot','Browser','Device','OS');
63
        $xmlData = array();
64
        foreach($xml as $name)
65
        {
66
            $xmlData[$name] = simplexml_load_file($this->getPathToData().strtolower($name).'.xml');
67
        }
68
        $this->setXmlData($xmlData);
69
    }
70
71
    public static function analyse($uaString='UA', $pathToData='auto')
0 ignored issues
show
Coding Style introduced by
analyse uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
72
    {
73
        $ua = $uaString;
74
        if($uaString == 'UA')
75
        {
76
            $ua = $_SERVER['HTTP_USER_AGENT'];
77
        }
78
79
        $detector = new Detector($pathToData);
80
        $xml = $detector->getXmlData();
81
82
        $detectorResult = new DetectorResult();
83
        $detectorResult->uaString = $ua;
84
        $ns = '\\EndorphinStudio\\Detector\\';
85
86
        foreach($xml as $key => $item)
87
        {
88
            $data = self::analysePart($xml,$key,$ua);
89
            $classname = $ns.$key;
90
            if($data !== null)
91
            {
92
                $object = new $classname($data);
93
                if($key == 'OS' || $key == 'Browser')
94
                {
95
                    $object->setVersion(self::getVersion($data, $ua));
96
                }
97
            }
98
            else
99
            {
100
                $object = $classname::initEmpty();
101
            }
102
            $detectorResult->$key = $object;
103
        }
104
105
        $detectorResult = self::checkRules($detectorResult);
106
107
        return $detectorResult;
108
    }
109
110
    /**
111
     * @param array $xmlData Xml data array
112
     * @param string $key Key in data array
113
     * @param string $uaString User agent
114
     * @return \SimpleXMLElement xml element
115
     */
116
    private static function analysePart($xmlData,$key,$uaString)
117
    {
118
        $data = $xmlData[$key]->data;
119
        foreach($data as $xmlItem)
120
        {
121
            $pattern = '/'.$xmlItem->pattern.'/';
122
            if(preg_match($pattern,$uaString))
123
            {
124
                return $xmlItem;
125
            }
126
        }
127
        return null;
128
    }
129
130
    /**
131
     * @param \SimpleXMLElement $xmlItem xmlItem
132
     * @param string $uaString User agent
133
     * @return string Version
134
     */
135
    private static function getVersion(\SimpleXMLElement $xmlItem,$uaString)
136
    {
137
        if($xmlItem !== null)
138
        {
139
            foreach($xmlItem->children() as $node)
140
            {
141
                if($node->getName() == 'versionPattern')
142
                {
143
                    $vPattern = $node->__toString();
144
                    $version = '/' . $vPattern . '(\/| )[\w-._]{1,15}/';
145
                    $uaString = str_replace(' NT', '', $uaString);
146
                    if (preg_match($version, $uaString)) {
147
                        preg_match($version, $uaString, $v);
148
                        $version = $v[0];
149
                        $version = preg_replace('/' . $vPattern . '/', '', $version);
150
                        $version = str_replace(';', '', $version);
151
                        $version = str_replace(' ', '', $version);
152
                        $version = str_replace('/', '', $version);
153
                        $version = str_replace('_', '.', $version);
154
155
                        if ($xmlItem->id == 'Windows') {
156
                            $version = self::getWindowsVersion($version);
157
                        }
158
159
                        return $version;
160
                    }
161
                }
162
            }
163
        }
164
        return D_NA;
165
    }
166
167
    /**
168
     * @param $version Windows number version
169
     * @return string Windows version
170
     */
171
    private static function getWindowsVersion($version)
172
    {
173
        $versions = array(
174
            '5.1' => 'XP',
175
            '5.2' => 'Server 2003',
176
            '6.0' => 'Vista',
177
            '6.1' => '7',
178
            '6.2' => '8',
179
            '6.3' => '8.1',
180
            '6.4' => '10'
181
        );
182
183
        return $versions[$version];
184
    }
185
186
    /**
187
     * @param DetectorResult $result Detector result
188
     * @return DetectorResult Final result
189
     */
190
    private static function checkRules(DetectorResult $result)
191
    {
192
        $Rules = DetectorRule::loadRulesFromFile();
193
        foreach($Rules as $rule)
194
        {
195
            $objectType = $rule->getObjectType();
196
            $objectProperty = $rule->getObjectProperty();
197
            $targetType = $rule->getTargetType();
198
            $targetValue = $rule->isTargetValue();
199
            $func = 'get'.$objectProperty;
200
            if($result->$objectType !== null)
201
            {
202
                if ($result->$objectType->$func() == $rule->getObjectPropertyValue()) {
203
                    $result->$targetType = $targetValue;
204
                    break;
205
                }
206
            }
207
        }
208
        return $result;
209
    }
210
}
211
define('D_NA','N\A');
212