Completed
Branch 4.0 (c710b5)
by Serhii
02:04
created

Detector::initialize()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

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