Completed
Push — v2.0 ( c502f2...cf0b32 )
by Serhii
02:20
created

Detector::__construct()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
76
        if($uaString == 'UA')
77
        {
78
            $ua = $_SERVER['HTTP_USER_AGENT'];
79
        }
80
81
        $detector = new Detector($pathToData);
82
        $xml = $detector->getXmlData();
83
        $data = array();
84
        foreach($xml as $key => $item)
85
        {
86
            $data[$key] = self::analysePart($xml,$key,$ua);
87
        }
88
89
        $detectorResult = new DetectorResult();
90
        $detectorResult->uaString = $ua;
91
92
        foreach($data as $key => $result)
93
        {
94
            switch($key)
95
            {
96
                case 'os':
97
                    $os = new OS($result);
98
                    $os->Version = self::getVersion($result,$ua);
99
                    $detectorResult->OS = $os;
0 ignored issues
show
Documentation Bug introduced by
It seems like $os of type object<EndorphinStudio\Detector\OS> is incompatible with the declared type object<EndorphinStudio\OS> of property $OS.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
100
                    break;
101
                case 'device':
102
                    $device = new Device($result);
103
                    $detectorResult->Device = $device;
0 ignored issues
show
Documentation Bug introduced by
It seems like $device of type object<EndorphinStudio\Detector\Device> is incompatible with the declared type object<EndorphinStudio\Device> of property $Device.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
104
                    break;
105
                case 'browser':
106
                    $browser = new Browser($result);
107
                    $browser->Version = self::getVersion($result,$ua);
108
                    $detectorResult->Browser = $browser;
0 ignored issues
show
Documentation Bug introduced by
It seems like $browser of type object<EndorphinStudio\Detector\Browser> is incompatible with the declared type object<EndorphinStudio\Browser> of property $Browser.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
109
                    break;
110
            }
111
        }
112
113
        return $detectorResult;
114
    }
115
116
    /**
117
     * @param array $xmlData Xml data array
118
     * @param string $key Key in data array
119
     * @param string $uaString User agent
120
     * @return \SimpleXMLElement xml element
121
     */
122
    private static function analysePart($xmlData,$key,$uaString)
123
    {
124
        $data = $xmlData[$key]->data;
125
        foreach($data as $xmlItem)
126
        {
127
            $pattern = '/'.$xmlItem->pattern.'/';
128
            if(preg_match($pattern,$uaString))
129
            {
130
                return $xmlItem;
131
            }
132
        }
133
        return null;
134
    }
135
136
    /**
137
     * @param \SimpleXMLElement $xmlItem xmlItem
138
     * @param string $uaString User agent
139
     * @return string Version
140
     */
141
    private static function getVersion($xmlItem,$uaString)
142
    {
143
        $vPattern = $xmlItem->versionPattern;
0 ignored issues
show
Bug introduced by
The property versionPattern does not seem to exist in SimpleXMLElement.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
144
        $version = @'/'.$vPattern.'(\/| )[\w-._]{1,15}/';
145
        $uaString = str_replace(' NT','',$uaString);
146
        if(preg_match($version,$uaString))
147
        {
148
            preg_match($version,$uaString,$v);
149
            @$version = $v[0];
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
150
            $version = preg_replace('/'.$vPattern.'/','',$version);
151
            $version = str_replace(';','',$version);
152
            $version = str_replace(' ','',$version);
153
            $version = str_replace('/','',$version);
154
            $version = str_replace('_','.',$version);
155
156
            if($xmlItem->id == 'Windows')
157
            {
158
                $version = self::getWindowsVersion($version);
159
            }
160
161
            return $version;
162
        }
163
        return null;
164
    }
165
166
    /**
167
     * @param $version Windows number version
168
     * @return string Windows version
169
     */
170
    private static function getWindowsVersion($version)
171
    {
172
        $versions = array(
173
            '5.1' => 'XP',
174
            '5.2' => 'Server 2003',
175
            '6.0' => 'Vista',
176
            '6.1' => '7',
177
            '6.2' => '8',
178
            '6.3' => '8.1',
179
            '6.4' => '10'
180
        );
181
182
        return $versions[$version];
183
    }
184
185
}