Completed
Push — master ( 7c4bfd...7dff86 )
by vistart
06:37 queued 27s
created

IPTrait::getIpAddress()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 9.2312

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 0
loc 21
ccs 9
cts 14
cp 0.6429
rs 7.551
cc 7
eloc 15
nc 7
nop 0
crap 9.2312
1
<?php
2
3
/**
4
 *  _   __ __ _____ _____ ___  ____  _____
5
 * | | / // // ___//_  _//   ||  __||_   _|
6
 * | |/ // /(__  )  / / / /| || |     | |
7
 * |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link http://vistart.name/
9
 * @copyright Copyright (c) 2016 vistart
10
 * @license http://vistart.name/license/
11
 */
12
13
namespace vistart\Models\traits;
14
15
use vistart\helpers\Ip;
16
use Yii;
17
use yii\web\Request;
18
19
/**
20
 * Entity features concerning IP address.
21
 * The EntityTrait use this trait by default. If you want to use this trait into
22
 * seperate models, please attach initialization events and merge the IP attributes
23
 * rules.
24
 * @property string|integer|null $ipAddress
25
 * @proeprty array $ipRules
26
 * @version 2.0
27
 * @author vistart <[email protected]>
28
 */
29
trait IPTrait
30
{
31
32
    /**
33
     * @var integer REQUIRED. Determine whether enabling the IP attributes and
34
     * features, and IP address type if enabled.
35
     * @since 1.1
36
     * @version 2.0
37
     */
38
    public $enableIP = 0x03;
39
40
    /**
41
     * @var integer Disable IP address features.
42
     */
43
    public static $noIp = 0x0;
44
45
    /**
46
     * @var integer Only accept IPv4 address.
47
     */
48
    public static $ipv4 = 0x1;
49
50
    /**
51
     * @var integer Only accept IPv6 address.
52
     */
53
    public static $ipv6 = 0x2;
54
55
    /**
56
     * @var integer Accept IPv4 and IPv6 address. Judge type of IP address
57
     * automatically.
58
     */
59
    public static $ipAll = 0x3;
60
61
    /**
62
     * @var string The attribute name that will receive the beginning 32 bits of
63
     * IPv6, or IPv4. The default value is 'ip_1'.
64
     */
65
    public $ipAttribute1 = 'ip_1';
66
67
    /**
68
     * @var string The attribute name that will receive the 33 - 64 bits of IPv6,
69
     * or 0 of IPv4. The default value is 'ip_2'.
70
     */
71
    public $ipAttribute2 = 'ip_2';
72
73
    /**
74
     * @var string The attribute name that will receive the 65 - 96 bits of IPv6,
75
     * or 0 of IPv4. The default value is 'ip_3'.
76
     */
77
    public $ipAttribute3 = 'ip_3';
78
79
    /**
80
     * @var string The attribute name that will receive the last 32 bits of IPv6,
81
     * or 0 of IPv4. The default value is 'ip_4'.
82
     */
83
    public $ipAttribute4 = 'ip_4';
84
85
    /**
86
     * @var string The attribute name that will receive the type of IP address.
87
     * The default value is 'ip_type'. If you assign $enableIP to $ipAll, this
88
     * attribute is required.
89
     */
90
    public $ipTypeAttribute = 'ip_type';
91
92
    /**
93
     * @var string Request component ID.
94
     */
95
    public $requestId = 'request';
96
97
    /**
98
     * Get web request component. if `$requestId` not specified, Yii::$app->request
99
     * will be taken.
100
     * @return Request
101
     */
102 55
    protected function getWebRequest()
103
    {
104 55
        $requestId = $this->requestId;
105 55
        if (!empty($requestId) && is_string($requestId)) {
106 55
            $request = Yii::$app->$requestId;
107 55
        } else {
108
            $request = Yii::$app->request;
109
        }
110 55
        if ($request instanceof Request) {
111 55
            return $request;
112
        }
113
        return null;
114
    }
115
116
    /**
117
     * Attach `onInitGuidAttribute` event.
118
     * @param string $eventName
119
     */
120 55
    protected function attachInitIpEvent($eventName)
121
    {
122 55
        $this->on($eventName, [$this, 'onInitIpAddress']);
0 ignored issues
show
Bug introduced by
It seems like on() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
123 55
    }
124
125
    /**
126
     * Initialize ip attributes.
127
     * This method is ONLY used for being triggered by event. DO NOT call,
128
     * override or modify it directly, unless you know the consequences.
129
     * @param \yii\base\Event $event
130
     * @since 1.1
131
     */
132 55
    public function onInitIpAddress($event)
133
    {
134 55
        $sender = $event->sender;
135
        /* @var $sender \vistart\Models\models\BaseEntityModel */
136 55
        $request = $sender->getWebRequest();
0 ignored issues
show
Bug introduced by
The method getWebRequest() cannot be called from this context as it is declared protected in class vistart\Models\traits\IPTrait.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
137 55
        if ($sender->enableIP && $request && empty($sender->ipAddress)) {
138 55
            $sender->ipAddress = $request->userIP;
139 55
        }
140 55
    }
141
142
    /**
143
     * Return the IP address.
144
     * The IP address is converted from ipAttribute*.
145
     * If you disable($this->enableIP = false) the IP feature, this method will
146
     * return null, or return the significantly IP address(Colon hexadecimal of
147
     * IPv6 or Dotted decimal of IPv4).
148
     * @return string|integer|null
149
     */
150 55
    public function getIpAddress()
151
    {
152 55
        if (!$this->enableIP) {
153
            return null;
154
        }
155 55
        if ($this->enableIP & static::$ipAll) {
156 55
            if ($this->{$this->ipTypeAttribute} == Ip::IPv4) {
157 1
                return $this->getIpv4Address();
158
            }
159 55
            if ($this->{$this->ipTypeAttribute} == Ip::IPv6) {
160 1
                return $this->getIpv6Address();
161
            }
162 55
        } else
163
        if ($this->enableIP & static::$ipv4) {
164
            return $this->getIpv4Address();
165
        } else
166
        if ($this->enableIP & static::$ipv6) {
167
            return $this->getIpv6Address();
168
        }
169 55
        return null;
170
    }
171
172
    /**
173
     * Get the IPv4 address.
174
     * @return string
175
     */
176 1
    private function getIpv4Address()
177
    {
178 1
        return Ip::long2ip($this->{$this->ipAttribute1});
179
    }
180
181
    /**
182
     * Get the IPv6 address.
183
     * @return string
184
     */
185 1
    private function getIpv6Address()
186
    {
187 1
        return Ip::LongtoIPv6(Ip::populateIPv6([
188 1
                    $this->{$this->ipAttribute1},
189 1
                    $this->{$this->ipAttribute2},
190 1
                    $this->{$this->ipAttribute3},
191 1
                    $this->{$this->ipAttribute4}
192 1
        ]));
193
    }
194
195
    /**
196
     * Convert the IP address to integer, and store it(them) to ipAttribute*.
197
     * If you disable($this->enableIP = false) the IP feature, this method will
198
     * be skipped(return null).
199
     * @param string $ipAddress the significantly IP address.
200
     * @return string|integer|null Integer when succeeded to convert.
201
     */
202 55
    public function setIpAddress($ipAddress)
203
    {
204 55
        if (!$ipAddress || !$this->enableIP) {
205 55
            return null;
206
        }
207 1
        $ipType = Ip::judgeIPtype($ipAddress);
208 1
        if ($ipType == Ip::IPv4 && $this->enableIP & static::$ipv4) {
209 1
            $this->{$this->ipAttribute1} = Ip::ip2long($ipAddress);
210 1
        } else
211 1
        if ($ipType == Ip::IPv6 && $this->enableIP & static::$ipv6) {
212 1
            $ips = Ip::splitIPv6(Ip::IPv6toLong($ipAddress));
213 1
            $this->{$this->ipAttribute1} = bindec($ips[0]);
214 1
            $this->{$this->ipAttribute2} = bindec($ips[1]);
215 1
            $this->{$this->ipAttribute3} = bindec($ips[2]);
216 1
            $this->{$this->ipAttribute4} = bindec($ips[3]);
217 1
        } else {
218 1
            return 0;
219
        }
220 1
        if ($this->enableIP & static::$ipAll) {
221 1
            $this->{$this->ipTypeAttribute} = $ipType;
222 1
        }
223 1
        return $ipType;
224
    }
225
226
    /**
227
     * Get the rules associated with ip attributes.
228
     * @return array
229
     */
230 17
    public function getIpRules()
231
    {
232 17
        $rules = [];
233 17
        if ($this->enableIP & static::$ipv6) {
234
            $rules = [
235 13
                [[$this->ipAttribute1,
236 13
                    $this->ipAttribute2,
237 13
                    $this->ipAttribute3,
238 13
                    $this->ipAttribute4],
239 13
                    'number', 'integerOnly' => true, 'min' => 0
240 13
                ],
241 13
            ];
242 13
        }
243 17
        if ($this->enableIP & static::$ipv4) {
244
            $rules = [
245 13
                [[$this->ipAttribute1],
246 13
                    'number', 'integerOnly' => true, 'min' => 0
247 13
                ],
248 13
            ];
249 13
        }
250 17
        if ($this->enableIP & static::$ipAll) {
251 13
            $rules[] = [
252 13
                [$this->ipTypeAttribute], 'in', 'range' => [Ip::IPv4, Ip::IPv6],
253
            ];
254 13
        }
255 17
        return $rules;
256
    }
257
258 16
    public function enabledIPFields()
259
    {
260 16
        $fields = [];
261 16
        switch ($this->enableIP) {
262 16
            case static::$ipAll:
263 15
                $fields[] = $this->ipTypeAttribute;
264 16
            case static::$ipv6:
265 15
                $fields[] = $this->ipAttribute2;
266 15
                $fields[] = $this->ipAttribute3;
267 15
                $fields[] = $this->ipAttribute4;
268 16
            case static::$ipv4:
269 15
                $fields[] = $this->ipAttribute1;
270 16
            case static::$noIp:
271 16
            default:
272 16
                break;
273 16
        }
274 16
        return $fields;
275
    }
276
}
277