Completed
Push — 3.0.0 ( 2c8b2b...8bb557 )
by Serhii
03:13
created

Detector   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 163
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 15
Bugs 0 Features 0
Metric Value
wmc 24
c 15
b 0
f 0
lcom 1
cbo 2
dl 0
loc 163
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 17 4
B analyse() 0 38 6
A analysePart() 0 13 3
B getVersion() 0 31 6
A getWindowsVersion() 0 14 1
A checkRules() 0 20 4
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', $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...
Unused Code introduced by
The parameter $pathToData is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

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
            }
62
            else
63
            {
64
                $object = $classname::initEmpty();
65
            }
66
            $detectorResult->$key = $object;
67
        }
68
69
        $detectorResult = self::checkRules($detectorResult);
70
71
        return $detectorResult;
72
    }
73
74
    /**
75
     * @param array $xmlData Xml data array
76
     * @param string $key Key in data array
77
     * @param string $uaString User agent
78
     * @return \SimpleXMLElement xml element
79
     */
80
    private static function analysePart($xmlData,$key,$uaString)
81
    {
82
        $data = $xmlData[$key]->data;
83
        foreach($data as $xmlItem)
84
        {
85
            $pattern = '/'.$xmlItem->pattern.'/';
86
            if(preg_match($pattern,$uaString))
87
            {
88
                return $xmlItem;
89
            }
90
        }
91
        return null;
92
    }
93
94
    /**
95
     * @param \SimpleXMLElement $xmlItem xmlItem
96
     * @param string $uaString User agent
97
     * @return string Version
98
     */
99
    private static function getVersion(\SimpleXMLElement $xmlItem,$uaString)
100
    {
101
        if($xmlItem !== null)
102
        {
103
            foreach($xmlItem->children() as $node)
104
            {
105
                if($node->getName() == 'versionPattern')
106
                {
107
                    $vPattern = $node->__toString();
108
                    $version = '/' . $vPattern . '(\/| )[\w-._]{1,15}/';
109
                    $uaString = str_replace(' NT', '', $uaString);
110
                    if (preg_match($version, $uaString)) {
111
                        preg_match($version, $uaString, $v);
112
                        $version = $v[0];
113
                        $version = preg_replace('/' . $vPattern . '/', '', $version);
114
                        $version = str_replace(';', '', $version);
115
                        $version = str_replace(' ', '', $version);
116
                        $version = str_replace('/', '', $version);
117
                        $version = str_replace('_', '.', $version);
118
119
                        if ($xmlItem->id == 'Windows') {
120
                            $version = self::getWindowsVersion($version);
121
                        }
122
123
                        return $version;
124
                    }
125
                }
126
            }
127
        }
128
        return D_NA;
129
    }
130
131
    /**
132
     * @param $version Windows number version
133
     * @return string Windows version
134
     */
135
    private static function getWindowsVersion($version)
136
    {
137
        $versions = array(
138
            '5.1' => 'XP',
139
            '5.2' => 'Server 2003',
140
            '6.0' => 'Vista',
141
            '6.1' => '7',
142
            '6.2' => '8',
143
            '6.3' => '8.1',
144
            '6.4' => '10'
145
        );
146
147
        return $versions[$version];
148
    }
149
150
    /**
151
     * @param DetectorResult $result Detector result
152
     * @return DetectorResult Final result
153
     */
154
    private static function checkRules(DetectorResult $result)
155
    {
156
        $Rules = DetectorRule::loadRulesFromFile();
157
        foreach($Rules as $rule)
158
        {
159
            $objectType = $rule->getObjectType();
160
            $objectProperty = $rule->getObjectProperty();
161
            $targetType = $rule->getTargetType();
162
            $targetValue = $rule->isTargetValue();
163
            $func = 'get'.$objectProperty;
164
            if($result->$objectType !== null)
165
            {
166
                if ($result->$objectType->$func() == $rule->getObjectPropertyValue()) {
167
                    $result->$targetType = $targetValue;
168
                    break;
169
                }
170
            }
171
        }
172
        return $result;
173
    }
174
}
175
define('D_NA','N\A');
176