GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 560332...66e815 )
by Robert
11:59
created

IpValidator::getClientOptions()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 31
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 0
cts 25
cp 0
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 23
nc 4
nop 2
crap 12
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\validators;
9
10
use Yii;
11
use yii\base\InvalidConfigException;
12
use yii\helpers\Html;
13
use yii\helpers\Json;
14
use yii\web\JsExpression;
15
16
/**
17
 * The validator checks if the attribute value is a valid IPv4/IPv6 address or subnet.
18
 *
19
 * It also may change attribute's value if normalization of IPv6 expansion is enabled.
20
 *
21
 * The following are examples of validation rules using this validator:
22
 *
23
 * ```php
24
 * ['ip_address', 'ip'], // IPv4 or IPv6 address
25
 * ['ip_address', 'ip', 'ipv6' => false], // IPv4 address (IPv6 is disabled)
26
 * ['ip_address', 'ip', 'subnet' => true], // requires a CIDR prefix (like 10.0.0.1/24) for the IP address
27
 * ['ip_address', 'ip', 'subnet' => null], // CIDR prefix is optional
28
 * ['ip_address', 'ip', 'subnet' => null, 'normalize' => true], // CIDR prefix is optional and will be added when missing
29
 * ['ip_address', 'ip', 'ranges' => ['192.168.0.0/24']], // only IP addresses from the specified subnet are allowed
30
 * ['ip_address', 'ip', 'ranges' => ['!192.168.0.0/24', 'any']], // any IP is allowed except IP in the specified subnet
31
 * ['ip_address', 'ip', 'expandIPv6' => true], // expands IPv6 address to a full notation format
32
 * ```
33
 *
34
 * @property array $ranges The IPv4 or IPv6 ranges that are allowed or forbidden. See [[setRanges()]] for
35
 * detailed description.
36
 *
37
 * @author Dmitry Naumenko <[email protected]>
38
 * @since 2.0.7
39
 */
40
class IpValidator extends Validator
41
{
42
    /**
43
     * The length of IPv6 address in bits
44
     */
45
    const IPV6_ADDRESS_LENGTH = 128;
46
    /**
47
     * The length of IPv4 address in bits
48
     */
49
    const IPV4_ADDRESS_LENGTH = 32;
50
    /**
51
     * Negation char. Used to negate [[ranges]] or [[networks]]
52
     * or to negate validating value when [[negation]] is set to `true`
53
     * @see negation
54
     * @see networks
55
     * @see ranges
56
     */
57
    const NEGATION_CHAR = '!';
58
59
    /**
60
     * @var array The network aliases, that can be used in [[ranges]].
61
     *  - key - alias name
62
     *  - value - array of strings. String can be an IP range, IP address or another alias. String can be
63
     *    negated with [[NEGATION_CHAR]] (independent of `negation` option).
64
     *
65
     * The following aliases are defined by default:
66
     *  - `*`: `any`
67
     *  - `any`: `0.0.0.0/0, ::/0`
68
     *  - `private`: `10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fd00::/8`
69
     *  - `multicast`: `224.0.0.0/4, ff00::/8`
70
     *  - `linklocal`: `169.254.0.0/16, fe80::/10`
71
     *  - `localhost`: `127.0.0.0/8', ::1`
72
     *  - `documentation`: `192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 2001:db8::/32`
73
     *  - `system`: `multicast, linklocal, localhost, documentation`
74
     *
75
     */
76
    public $networks = [
77
        '*' => ['any'],
78
        'any' => ['0.0.0.0/0', '::/0'],
79
        'private' => ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', 'fd00::/8'],
80
        'multicast' => ['224.0.0.0/4', 'ff00::/8'],
81
        'linklocal' => ['169.254.0.0/16', 'fe80::/10'],
82
        'localhost' => ['127.0.0.0/8', '::1'],
83
        'documentation' => ['192.0.2.0/24', '198.51.100.0/24', '203.0.113.0/24', '2001:db8::/32'],
84
        'system' => ['multicast', 'linklocal', 'localhost', 'documentation'],
85
    ];
86
    /**
87
     * @var bool whether the validating value can be an IPv6 address. Defaults to `true`.
88
     */
89
    public $ipv6 = true;
90
    /**
91
     * @var bool whether the validating value can be an IPv4 address. Defaults to `true`.
92
     */
93
    public $ipv4 = true;
94
    /**
95
     * @var bool whether the address can be an IP with CIDR subnet, like `192.168.10.0/24`.
96
     * The following values are possible:
97
     *
98
     * - `false` - the address must not have a subnet (default).
99
     * - `true` - specifying a subnet is required.
100
     * - `null` - specifying a subnet is optional.
101
     */
102
    public $subnet = false;
103
    /**
104
     * @var bool whether to add the CIDR prefix with the smallest length (32 for IPv4 and 128 for IPv6) to an
105
     * address without it. Works only when `subnet` is not `false`. For example:
106
     *  - `10.0.1.5` will normalized to `10.0.1.5/32`
107
     *  - `2008:db0::1` will be normalized to `2008:db0::1/128`
108
     *    Defaults to `false`.
109
     * @see subnet
110
     */
111
    public $normalize = false;
112
    /**
113
     * @var bool whether address may have a [[NEGATION_CHAR]] character at the beginning.
114
     * Defaults to `false`.
115
     */
116
    public $negation = false;
117
    /**
118
     * @var bool whether to expand an IPv6 address to the full notation format.
119
     * Defaults to `false`.
120
     */
121
    public $expandIPv6 = false;
122
    /**
123
     * @var string Regexp-pattern to validate IPv4 address
124
     */
125
    public $ipv4Pattern = '/^(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9])\.){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))$/';
126
    /**
127
     * @var string Regexp-pattern to validate IPv6 address
128
     */
129
    public $ipv6Pattern = '/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/';
130
    /**
131
     * @var string user-defined error message is used when validation fails due to the wrong IP address format.
132
     *
133
     * You may use the following placeholders in the message:
134
     *
135
     * - `{attribute}`: the label of the attribute being validated
136
     * - `{value}`: the value of the attribute being validated
137
     */
138
    public $message;
139
    /**
140
     * @var string user-defined error message is used when validation fails due to the disabled IPv6 validation.
141
     *
142
     * You may use the following placeholders in the message:
143
     *
144
     * - `{attribute}`: the label of the attribute being validated
145
     * - `{value}`: the value of the attribute being validated
146
     *
147
     * @see ipv6
148
     */
149
    public $ipv6NotAllowed;
150
    /**
151
     * @var string user-defined error message is used when validation fails due to the disabled IPv4 validation.
152
     *
153
     * You may use the following placeholders in the message:
154
     *
155
     * - `{attribute}`: the label of the attribute being validated
156
     * - `{value}`: the value of the attribute being validated
157
     *
158
     * @see ipv4
159
     */
160
    public $ipv4NotAllowed;
161
    /**
162
     * @var string user-defined error message is used when validation fails due to the wrong CIDR.
163
     *
164
     * You may use the following placeholders in the message:
165
     *
166
     * - `{attribute}`: the label of the attribute being validated
167
     * - `{value}`: the value of the attribute being validated
168
     * @see subnet
169
     */
170
    public $wrongCidr;
171
    /**
172
     * @var string user-defined error message is used when validation fails due to subnet [[subnet]] set to 'only',
173
     * but the CIDR prefix is not set.
174
     *
175
     * You may use the following placeholders in the message:
176
     *
177
     * - `{attribute}`: the label of the attribute being validated
178
     * - `{value}`: the value of the attribute being validated
179
     *
180
     * @see subnet
181
     */
182
    public $noSubnet;
183
    /**
184
     * @var string user-defined error message is used when validation fails
185
     * due to [[subnet]] is false, but CIDR prefix is present.
186
     *
187
     * You may use the following placeholders in the message:
188
     *
189
     * - `{attribute}`: the label of the attribute being validated
190
     * - `{value}`: the value of the attribute being validated
191
     *
192
     * @see subnet
193
     */
194
    public $hasSubnet;
195
    /**
196
     * @var string user-defined error message is used when validation fails due to IP address
197
     * is not not allowed by [[ranges]] check.
198
     *
199
     * You may use the following placeholders in the message:
200
     *
201
     * - `{attribute}`: the label of the attribute being validated
202
     * - `{value}`: the value of the attribute being validated
203
     *
204
     * @see ranges
205
     */
206
    public $notInRange;
207
208
    /**
209
     * @var array
210
     */
211
    private $_ranges = [];
212
213
214
    /**
215
     * @inheritdoc
216
     */
217 26
    public function init()
218
    {
219 26
        parent::init();
220
221 26
        if (!$this->ipv4 && !$this->ipv6) {
222 1
            throw new InvalidConfigException('Both IPv4 and IPv6 checks can not be disabled at the same time');
223
        }
224
225 25
        if (!defined('AF_INET6') && $this->ipv6) {
226
            throw new InvalidConfigException('IPv6 validation can not be used. PHP is compiled without IPv6');
227
        }
228
229 25
        if ($this->message === null) {
230 25
            $this->message = Yii::t('yii', '{attribute} must be a valid IP address.');
231 25
        }
232 25
        if ($this->ipv6NotAllowed === null) {
233 25
            $this->ipv6NotAllowed = Yii::t('yii', '{attribute} must not be an IPv6 address.');
234 25
        }
235 25
        if ($this->ipv4NotAllowed === null) {
236 25
            $this->ipv4NotAllowed = Yii::t('yii', '{attribute} must not be an IPv4 address.');
237 25
        }
238 25
        if ($this->wrongCidr === null) {
239 25
            $this->wrongCidr = Yii::t('yii', '{attribute} contains wrong subnet mask.');
240 25
        }
241 25
        if ($this->noSubnet === null) {
242 25
            $this->noSubnet = Yii::t('yii', '{attribute} must be an IP address with specified subnet.');
243 25
        }
244 25
        if ($this->hasSubnet === null) {
245 25
            $this->hasSubnet = Yii::t('yii', '{attribute} must not be a subnet.');
246 25
        }
247 25
        if ($this->notInRange === null) {
248 25
            $this->notInRange = Yii::t('yii', '{attribute} is not in the allowed range.');
249 25
        }
250 25
    }
251
252
    /**
253
     * Set the IPv4 or IPv6 ranges that are allowed or forbidden.
254
     *
255
     * The following preparation tasks are performed:
256
     *
257
     * - Recursively substitutes aliases (described in [[networks]]) with their values.
258
     * - Removes duplicates
259
     *
260
     * @property array the IPv4 or IPv6 ranges that are allowed or forbidden.
261
     * See [[setRanges()]] for detailed description.
262
     * @param array $ranges the IPv4 or IPv6 ranges that are allowed or forbidden.
263
     *
264
     * When the array is empty, or the option not set, all IP addresses are allowed.
265
     *
266
     * Otherwise, the rules are checked sequentially until the first match is found.
267
     * An IP address is forbidden, when it has not matched any of the rules.
268
     *
269
     * Example:
270
     *
271
     * ```php
272
     * [
273
     *      'ranges' => [
274
     *          '192.168.10.128'
275
     *          '!192.168.10.0/24',
276
     *          'any' // allows any other IP addresses
277
     *      ]
278
     * ]
279
     * ```
280
     *
281
     * In this example, access is allowed for all the IPv4 and IPv6 addresses excluding the `192.168.10.0/24` subnet.
282
     * IPv4 address `192.168.10.128` is also allowed, because it is listed before the restriction.
283
     */
284 8
    public function setRanges($ranges)
285
    {
286 8
        $this->_ranges = $this->prepareRanges((array) $ranges);
287 8
    }
288
289
    /**
290
     * @return array The IPv4 or IPv6 ranges that are allowed or forbidden.
291
     */
292 13
    public function getRanges()
293
    {
294 13
        return $this->_ranges;
295
    }
296
297
    /**
298
     * @inheritdoc
299
     */
300 13
    protected function validateValue($value)
301
    {
302 13
        $result = $this->validateSubnet($value);
303 13
        if (is_array($result)) {
304 13
            $result[1] = array_merge(['ip' => is_array($value) ? 'array()' : $value], $result[1]);
305 13
            return $result;
306
        } else {
307 7
            return null;
308
        }
309
    }
310
311
    /**
312
     * @inheritdoc
313
     */
314 8
    public function validateAttribute($model, $attribute)
315
    {
316 8
        $value = $model->$attribute;
317
318 8
        $result = $this->validateSubnet($value);
319 8
        if (is_array($result)) {
320 8
            $result[1] = array_merge(['ip' => is_array($value) ? 'array()' : $value], $result[1]);
321 8
            $this->addError($model, $attribute, $result[0], $result[1]);
322 8
        } else {
323 2
            $model->$attribute = $result;
324
        }
325 8
    }
326
327
    /**
328
     * Validates an IPv4/IPv6 address or subnet
329
     *
330
     * @param $ip string
331
     * @return string|array
332
     * string - the validation was successful;
333
     * array  - an error occurred during the validation.
334
     * Array[0] contains the text of an error, array[1] contains values for the placeholders in the error message
335
     */
336 21
    private function validateSubnet($ip)
337
    {
338 21
        if (!is_string($ip)) {
339 8
            return [$this->message, []];
340
        }
341
342 13
        $negation = null;
343 13
        $cidr = null;
344 13
        $isCidrDefault = false;
345
346 13
        if (preg_match($this->getIpParsePattern(), $ip, $matches)) {
347 13
            $negation = ($matches[1] !== '') ? $matches[1] : null;
348 13
            $ip = $matches[2];
349 13
            $cidr = isset($matches[4]) ? $matches[4] : null;
350 13
        }
351
352 13
        if ($this->subnet === true && $cidr === null) {
353 3
            return [$this->noSubnet, []];
354
        }
355 13
        if ($this->subnet === false && $cidr !== null) {
356 5
            return [$this->hasSubnet, []];
357
        }
358 13
        if ($this->negation === false && $negation !== null) {
359 3
            return [$this->message, []];
360
        }
361
362 13
        if ($this->getIpVersion($ip) == 6) {
363 8
            if ($cidr !== null) {
364 3
                if ($cidr > static::IPV6_ADDRESS_LENGTH || $cidr < 0) {
365 3
                    return [$this->wrongCidr, []];
366
                }
367 3
            } else {
368 8
                $isCidrDefault = true;
369 8
                $cidr = static::IPV6_ADDRESS_LENGTH;
370
            }
371
372 8
            if (!$this->validateIPv6($ip)) {
373 4
                return [$this->message, []];
374
            }
375 6
            if (!$this->ipv6) {
376 2
                return [$this->ipv6NotAllowed, []];
377
            }
378
379 6
            if ($this->expandIPv6) {
380 1
                $ip = $this->expandIPv6($ip);
381 1
            }
382 6
        } else {
383 8
            if ($cidr !== null) {
384 4
                if ($cidr > static::IPV4_ADDRESS_LENGTH || $cidr < 0) {
385 2
                    return [$this->wrongCidr, []];
386
                }
387 4
            } else {
388 8
                $isCidrDefault = true;
389 8
                $cidr = static::IPV4_ADDRESS_LENGTH;
390
            }
391 8
            if (!$this->validateIPv4($ip)) {
392 4
                return [$this->message, []];
393
            }
394 6
            if (!$this->ipv4) {
395 2
                return [$this->ipv4NotAllowed, []];
396
            }
397
        }
398
399 9
        if (!$this->isAllowed($ip, $cidr)) {
400 4
            return [$this->notInRange, []];
401
        }
402
403 9
        $result = $negation . $ip;
404
405 9
        if ($this->subnet !== false && (!$isCidrDefault || $isCidrDefault && $this->normalize)) {
406 7
            $result .= "/$cidr";
407 7
        }
408
409 9
        return $result;
410
    }
411
412
    /**
413
     * Expands an IPv6 address to it's full notation. For example `2001:db8::1` will be
414
     * expanded to `2001:0db8:0000:0000:0000:0000:0000:0001`
415
     *
416
     * @param string $ip the original IPv6
417
     * @return string the expanded IPv6
418
     */
419 1
    private function expandIPv6($ip)
420
    {
421 1
        $hex = unpack('H*hex', inet_pton($ip));
422 1
        return substr(preg_replace('/([a-f0-9]{4})/i', '$1:', $hex['hex']), 0, -1);
423
    }
424
425
    /**
426
     * The method checks whether the IP address with specified CIDR is allowed according to the [[ranges]] list.
427
     *
428
     * @param string $ip
429
     * @param int $cidr
430
     * @return bool
431
     * @see ranges
432
     */
433 9
    private function isAllowed($ip, $cidr)
434
    {
435 9
        if (empty($this->ranges)) {
436 5
            return true;
437
        }
438
439 4
        foreach ($this->ranges as $string) {
440 4
            list($isNegated, $range) = $this->parseNegatedRange($string);
441 4
            if ($this->inRange($ip, $cidr, $range)) {
442 4
                return !$isNegated;
443
            }
444 4
        }
445
446 3
        return false;
447
    }
448
449
    /**
450
     * Parses IP address/range for the negation with [[NEGATION_CHAR]].
451
     *
452
     * @param $string
453
     * @return array `[0 => bool, 1 => string]`
454
     *  - boolean: whether the string is negated
455
     *  - string: the string without negation (when the negation were present)
456
     */
457 8
    private function parseNegatedRange($string)
458
    {
459 8
        $isNegated = strpos($string, static::NEGATION_CHAR) === 0;
460 8
        return [$isNegated, $isNegated ? substr($string, strlen(static::NEGATION_CHAR)) : $string];
461
    }
462
463
    /**
464
     * Prepares array to fill in [[ranges]]:
465
     *  - Recursively substitutes aliases, described in [[networks]] with their values
466
     *  - Removes duplicates
467
     *
468
     *
469
     * @param $ranges
470
     * @return array
471
     * @see networks
472
     */
473 8
    private function prepareRanges($ranges)
474
    {
475 8
        $result = [];
476 8
        foreach ($ranges as $string) {
477 8
            list($isRangeNegated, $range) = $this->parseNegatedRange($string);
478 8
            if (isset($this->networks[$range])) {
479 6
                $replacements = $this->prepareRanges($this->networks[$range]);
480 6
                foreach ($replacements as &$replacement) {
481 6
                    list($isReplacementNegated, $replacement) = $this->parseNegatedRange($replacement);
482 6
                    $result[] = ($isRangeNegated && !$isReplacementNegated ? static::NEGATION_CHAR : '') . $replacement;
483 6
                }
484 6
            } else {
485 8
                $result[] = $string;
486
            }
487 8
        }
488 8
        return array_unique($result);
489
    }
490
491
    /**
492
     * Validates IPv4 address
493
     *
494
     * @param string $value
495
     * @return bool
496
     */
497 8
    protected function validateIPv4($value)
498
    {
499 8
        return preg_match($this->ipv4Pattern, $value) !== 0;
500
    }
501
502
    /**
503
     * Validates IPv6 address
504
     *
505
     * @param string $value
506
     * @return bool
507
     */
508 8
    protected function validateIPv6($value)
509
    {
510 8
        return preg_match($this->ipv6Pattern, $value) !== 0;
511
    }
512
513
    /**
514
     * Gets the IP version
515
     *
516
     * @param string $ip
517
     * @return int
518
     */
519 13
    private function getIpVersion($ip)
520
    {
521 13
        return strpos($ip, ':') === false ? 4 : 6;
522
    }
523
524
    /**
525
     * Used to get the Regexp pattern for initial IP address parsing
526
     * @return string
527
     */
528 13
    private function getIpParsePattern()
529
    {
530 13
        return '/^(' . preg_quote(static::NEGATION_CHAR) . '?)(.+?)(\/(\d+))?$/';
531
    }
532
533
    /**
534
     * Checks whether the IP is in subnet range
535
     *
536
     * @param string $ip an IPv4 or IPv6 address
537
     * @param int $cidr
538
     * @param string $range subnet in CIDR format e.g. `10.0.0.0/8` or `2001:af::/64`
539
     * @return bool
540
     */
541 4
    private function inRange($ip, $cidr, $range)
542
    {
543 4
        $ipVersion = $this->getIpVersion($ip);
544 4
        $binIp = $this->ip2bin($ip);
545
546 4
        $parts = explode('/', $range);
547 4
        $net = array_shift($parts);
548 4
        $range_cidr = array_shift($parts);
549
550
551 4
        $netVersion = $this->getIpVersion($net);
552 4
        if ($ipVersion !== $netVersion) {
553 2
            return false;
554
        }
555 4
        if ($range_cidr === null) {
556 2
            $range_cidr = $netVersion === 4 ? static::IPV4_ADDRESS_LENGTH : static::IPV6_ADDRESS_LENGTH;
557 2
        }
558
559 4
        $binNet = $this->ip2bin($net);
560 4
        return substr($binIp, 0, $range_cidr) === substr($binNet, 0, $range_cidr) && $cidr >= $range_cidr;
561
    }
562
563
    /**
564
     * Converts IP address to bits representation
565
     *
566
     * @param string $ip
567
     * @return string bits as a string
568
     */
569 4
    private function ip2bin($ip)
570
    {
571 4
        if ($this->getIpVersion($ip) === 4) {
572 3
            return str_pad(base_convert(ip2long($ip), 10, 2), static::IPV4_ADDRESS_LENGTH, '0', STR_PAD_LEFT);
573
        } else {
574 3
            $unpack = unpack('A16', inet_pton($ip));
575 3
            $binStr = array_shift($unpack);
576 3
            $bytes = static::IPV6_ADDRESS_LENGTH / 8; // 128 bit / 8 = 16 bytes
577 3
            $result = '';
578 3
            while ($bytes-- > 0) {
579 3
                $result = sprintf('%08b', isset($binStr[$bytes]) ? ord($binStr[$bytes]) : '0') . $result;
580 3
            }
581 3
            return $result;
582
        }
583
    }
584
585
    /**
586
     * @inheritdoc
587
     */
588
    public function clientValidateAttribute($model, $attribute, $view)
589
    {
590
        ValidationAsset::register($view);
591
        $options = $this->getClientOptions($model, $attribute);
592
593
        return 'yii.validation.ip(value, messages, ' . Json::htmlEncode($options) . ');';
594
    }
595
596
    /**
597
     * @inheritdoc
598
     */
599
    public function getClientOptions($model, $attribute)
600
    {
601
        $messages = [
602
            'ipv6NotAllowed' => $this->ipv6NotAllowed,
603
            'ipv4NotAllowed' => $this->ipv4NotAllowed,
604
            'message' => $this->message,
605
            'noSubnet' => $this->noSubnet,
606
            'hasSubnet' => $this->hasSubnet,
607
        ];
608
        foreach ($messages as &$message) {
609
            $message = Yii::$app->getI18n()->format($message, [
610
                'attribute' => $model->getAttributeLabel($attribute),
611
            ], Yii::$app->language);
612
        }
613
614
        $options = [
615
            'ipv4Pattern' => new JsExpression(Html::escapeJsRegularExpression($this->ipv4Pattern)),
616
            'ipv6Pattern' => new JsExpression(Html::escapeJsRegularExpression($this->ipv6Pattern)),
617
            'messages' => $messages,
618
            'ipv4' => (bool) $this->ipv4,
619
            'ipv6' => (bool) $this->ipv6,
620
            'ipParsePattern' => new JsExpression(Html::escapeJsRegularExpression($this->getIpParsePattern())),
621
            'negation' => $this->negation,
622
            'subnet' => $this->subnet,
623
        ];
624
        if ($this->skipOnEmpty) {
625
            $options['skipOnEmpty'] = 1;
626
        }
627
628
        return $options;
629
    }
630
}
631