Completed
Push — 3.0.0 ( d1c058...ad698c )
by Serhii
03:01
created

Detector::analyse()   C

Complexity

Conditions 7
Paths 16

Size

Total Lines 42
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

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