Completed
Push — 3.0.0 ( e168bd...cd1823 )
by Serhii
02:34
created

Detector   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 18
Bugs 0 Features 0
Metric Value
wmc 30
c 18
b 0
f 0
lcom 1
cbo 4
dl 0
loc 197
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 17 4
C analyse() 0 46 8
A analysePart() 0 13 3
B getVersion() 0 31 6
B getWindowsVersion() 0 25 2
A checkRules() 0 20 4
A checkModelName() 0 14 3
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
    /** @var array Xml Data */
15
    public static $xmlData;
16
17
    private static function init($pathToData = 'auto')
18
    {
19
        if ($pathToData == 'auto')
20
        {
21
            $pathToData = str_replace('src', 'data', __DIR__) . '/';
22
        }
23
24
        if (self::$xmlData === null)
25
        {
26
            $xml = array('Robot', 'Browser', 'Device', 'OS');
27
            $xmlData = array();
28
            foreach ($xml as $name) {
29
                $xmlData[$name] = simplexml_load_file($pathToData . strtolower($name) . '.xml');
30
            }
31
            self::$xmlData = $xmlData;
32
        }
33
    }
34
35
    public static function analyse($uaString='UA')
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...
36
    {
37
        $ua = $uaString;
38
        if($uaString == 'UA')
39
        {
40
            $ua = $_SERVER['HTTP_USER_AGENT'];
41
        }
42
43
        Detector::init();
44
        $xml = Detector::$xmlData;
45
46
        $detectorResult = new DetectorResult();
47
        $detectorResult->uaString = $ua;
48
        $ns = '\\EndorphinStudio\\Detector\\';
49
50
        foreach($xml as $key => $item)
51
        {
52
            $data = self::analysePart($xml,$key,$ua);
53
            $classname = $ns.$key;
54
            if($data !== null)
55
            {
56
                $object = new $classname($data);
57
                if($key == 'OS' || $key == 'Browser')
58
                {
59
                    $object->setVersion(self::getVersion($data, $ua));
60
                }
61
                if($key == 'Robot')
62
                {
63
                    if($object->getName() != D_NA)
64
                    {
65
                        $detectorResult->isBot = true;
66
                    }
67
                }
68
            }
69
            else
70
            {
71
                $object = $classname::initEmpty();
72
            }
73
            $detectorResult->$key = $object;
74
        }
75
76
        $detectorResult = self::checkRules($detectorResult);
77
        $detectorResult = self::checkModelName($detectorResult);
78
79
        return $detectorResult;
80
    }
81
82
    /**
83
     * @param array $xmlData Xml data array
84
     * @param string $key Key in data array
85
     * @param string $uaString User agent
86
     * @return \SimpleXMLElement xml element
87
     */
88
    private static function analysePart($xmlData,$key,$uaString)
89
    {
90
        $data = $xmlData[$key]->data;
91
        foreach($data as $xmlItem)
92
        {
93
            $pattern = '/'.$xmlItem->pattern.'/';
94
            if(preg_match($pattern,$uaString))
95
            {
96
                return $xmlItem;
97
            }
98
        }
99
        return null;
100
    }
101
102
    /**
103
     * @param \SimpleXMLElement $xmlItem xmlItem
104
     * @param string $uaString User agent
105
     * @return string Version
106
     */
107
    private static function getVersion(\SimpleXMLElement $xmlItem,$uaString)
108
    {
109
        if($xmlItem !== null)
110
        {
111
            foreach($xmlItem->children() as $node)
112
            {
113
                if($node->getName() == 'versionPattern')
114
                {
115
                    $vPattern = $node->__toString();
116
                    $version = '/' . $vPattern . '(\/| )[\w-._]{1,15}/';
117
                    $uaString = str_replace(' NT', '', $uaString);
118
                    if (preg_match($version, $uaString)) {
119
                        preg_match($version, $uaString, $v);
120
                        $version = $v[0];
121
                        $version = preg_replace('/' . $vPattern . '/', '', $version);
122
                        $version = str_replace(';', '', $version);
123
                        $version = str_replace(' ', '', $version);
124
                        $version = str_replace('/', '', $version);
125
                        $version = str_replace('_', '.', $version);
126
127
                        if ($xmlItem->id == 'Windows') {
128
                            $version = self::getWindowsVersion($version);
129
                        }
130
131
                        return $version;
132
                    }
133
                }
134
            }
135
        }
136
        return D_NA;
137
    }
138
139
    /**
140
     * @param $version Windows number version
141
     * @return string Windows version
142
     */
143
    private static function getWindowsVersion($version)
144
    {
145
        $versions = array(
146
            '95' => '95',
147
            '3.1' => '3.1',
148
            '3.5' => '3.5',
149
            '3.51' => '3.51',
150
            '4.0' => '4.0',
151
            '2000' => '2000',
152
            '5.0' => '2000',
153
            '5.1' => 'XP',
154
            '5.2' => 'Server 2003',
155
            '6.0' => 'Vista',
156
            '6.1' => '7',
157
            '6.2' => '8',
158
            '6.3' => '8.1',
159
            '6.4' => '10',
160
            '10.0' => '10'
161
        );
162
163
        if(array_key_exists(strval($version),$versions))
164
            return $versions[strval($version)];
165
        else
166
            return D_NA;
167
    }
168
169
    /**
170
     * @param DetectorResult $result Detector result
171
     * @return DetectorResult Final result
172
     */
173
    private static function checkRules(DetectorResult $result)
174
    {
175
        $Rules = DetectorRule::loadRulesFromFile();
176
        foreach($Rules as $rule)
177
        {
178
            $objectType = $rule->getObjectType();
179
            $objectProperty = $rule->getObjectProperty();
180
            $targetType = $rule->getTargetType();
181
            $targetValue = $rule->isTargetValue();
182
            $func = 'get'.$objectProperty;
183
            if($result->$objectType !== null)
184
            {
185
                if ($result->$objectType->$func() == $rule->getObjectPropertyValue()) {
186
                    $result->$targetType = $targetValue;
187
                    break;
188
                }
189
            }
190
        }
191
        return $result;
192
    }
193
194
    private static function checkModelName(DetectorResult $result)
195
    {
196
        $models = DeviceModel::loadFromFile();
197
        foreach($models as $model)
198
        {
199
            if($model->getDeviceName() === $result->Device->getName())
200
            {
201
                $pattern = '/'.$model->getPattern().'/';
202
                preg_match($pattern,$result->uaString,$match);
203
                $result->Device->setModelName($match[1]);
204
            }
205
        }
206
        return $result;
207
    }
208
}
209
define('D_NA','N\A');
210