Test Failed
Push — master ( 1394e6...2e6134 )
by Feyman
02:46
created

IpInfo   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 83.67%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 20
lcom 1
cbo 3
dl 0
loc 164
c 1
b 0
f 0
ccs 41
cts 49
cp 0.8367
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A info() 0 4 1
A __call() 0 9 2
A __construct() 0 5 1
A address() 0 16 2
A getOutTime() 0 4 1
A setOutTime() 0 6 1
A query() 0 18 4
A apiQuery() 0 4 1
A localQuery() 0 4 1
A isInternal() 0 10 4
A snakeCase() 0 9 2
1
<?php
2
3
namespace IpInfo;
4
5
6
use IpInfo\Exceptions\GetIpIpInfoFailedException;
7
use IpInfo\Exceptions\IpIllegalException;
8
use IpInfo\Exceptions\MethodNotExistException;
9
10
/**
11
 * Class IpInfo
12
 * @package IpInfo
13
 */
14
class IpInfo
15
{
16
    /**
17
     * @var
18
     */
19
    private $ip;
20
    /**
21
     * @var
22
     */
23
    private $info = [
24
        'ip'      => '',
25
        'country' => '',
26
        'area'    => '',
27
        'region'  => '',
28
        'city'    => '',
29
        'county'  => '',
30
        'isp'     => '',
31
    ];
32
    /**
33
     * 请求淘宝 IP 库 api 超时时间
34
     * @var int
35
     */
36 8
    private $outTime = 1;
37
38 8
    /**
39 8
     * IpInfo constructor.
40
     *
41
     * @param $ip
42 8
     *
43 8
     * @throws IpIllegalException
44
     */
45
    public function __construct($ip)
46
    {
47
        $this->ip = $ip;
48
        $this->query();
49
    }
50
51 8
    /**
52
     * @param string $delimiter
53 8
     * @param bool   $full
54
     *
55
     * @return string
56 8
     */
57
    public function address($delimiter = ' ', $full = false)
58
    {
59
        $struct = [
60 8
            $this->info['country'],
61 8
            $this->info['area'],
62 8
            $this->info['region'],
63 8
            $this->info['city'],
64 8
            $this->info['county'],
65 8
        ];
66 8
        if (!$full) {
67 8
            array_splice($struct, 1, 1);
68 8
        }
69 8
        $struct = array_filter($struct);
70
71 8
        return implode($delimiter, $struct);
72
    }
73
74
    /**
75
     * @return array ip 的信息
76
     */
77 1
    public function info()
78
    {
79 1
        return $this->info;
80
    }
81
82
    /**
83
     * @param $name
84
     * @param $arguments
85
     *
86
     * @return mixed
87
     * @throws MethodNotExistException
88
     */
89 7
    public function __call($name, $arguments)
90
    {
91
92 7
        if (isset($this->info, $name)) {
93 7
            return $this->info[$this->snakeCase($name)];
94
        } else {
95
            throw new MethodNotExistException('Call a Not Exist Method:' . $name);
96
        }
97
    }
98
99
    /**
100
     * @return mixed
101
     */
102 8
    public function getOutTime()
103
    {
104 8
        return $this->outTime;
105 8
    }
106 8
107
    /**
108
     * @param mixed $outTime
109 8
     *
110
     * @return $this
111 8
     */
112
    public function setOutTime($outTime)
113
    {
114
        $this->outTime = $outTime;
115
116 8
        return $this;
117
    }
118 8
119
    /**
120
     * @throws GetIpIpInfoFailedException
121 8
     */
122
    private function query()
123 8
    {
124 8
        $this->info['ip'] = $this->ip;
125 8
        if ($this->ip === '127.0.0.1') {
126 8
            $this->info['country'] = '本机';
127
        } elseif ($this->isInternal()) {
128 8
            $this->info['country'] = 'INNA 保留地址';
129
        } else {
130
            // 先通过 api 获取,api 获取失败的话通过本地数据库获取
131
            $result = $this->apiQuery();
132
            if ($result === false) {
133
                // api 获取失败的话进行本地获取
134
                $result = $this->localQuery();
135
            }
136
137 7
            $this->info = $result;
138
        }
139 7
    }
140
141
    private function apiQuery()
142
    {
143
        return (new IpTaobaoApiQuery)->setOutTime($this->outTime)->query($this->ip);
144 7
    }
145
146
    private function localQuery()
147
    {
148
        return IpLocalQuery::create()->query($this->ip);
149
    }
150
151
    private function isInternal()
152
    {
153
        $ipLong   = ip2long($this->ip);
154
        $netLocal = ip2long('127.255.255.255') >> 24; //127.x.x.x
155
        $netA     = ip2long('10.255.255.255') >> 24; //A类网预留ip的网络地址
156
        $netB     = ip2long('172.31.255.255') >> 20; //B类网预留ip的网络地址
157
        $netC     = ip2long('192.168.255.255') >> 16; //C类网预留ip的网络地址
158
159
        return $ipLong >> 24 === $netLocal || $ipLong >> 24 === $netA || $ipLong >> 20 === $netB || $ipLong >> 16 === $netC;
160
    }
161
162
    /**
163
     * @param        $value
164
     * @param string $delimiter
165
     *
166
     * @return mixed|string
167
     */
168
    private function snakeCase($value, $delimiter = '_')
169
    {
170
        if (!ctype_lower($value)) {
171
            $value = preg_replace('/\s+/u', '', $value);
172
            $value = strtolower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value));
173
        }
174
175
        return $value;
176
    }
177
}