Apply contribution guidelines to "Ip" rule

Co-authored-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
Henrique Moody 2018-12-07 19:16:42 +01:00
parent 73f9380d9e
commit 2aaec39dbb
No known key found for this signature in database
GPG key ID: 221E9281655813A6
11 changed files with 200 additions and 270 deletions

View file

@ -1,10 +1,12 @@
# Ip
- `Ip()`
- `Ip(mixed $options)`
- `Ip(string $range)`
- `Ip(int $options)`
Validates IP Addresses. This validator uses the native filter_var()
PHP function.
Validates whether the input is a valid IP address.
This validator uses the native [filter_var()][] PHP function.
```php
v::ip()->validate('127.0.0.1'); // true
@ -12,7 +14,7 @@ v::ip('220.78.168.0/21')->validate('220.78.173.2'); // true
v::ip('220.78.168.0/21')->validate('220.78.176.2'); // false
```
You can pass a parameter with filter_var flags for IP.
You can pass a parameter with [filter_var()][] flags for IP.
```php
v::ip(FILTER_FLAG_NO_PRIV_RANGE)->validate('192.168.0.1'); // false
@ -22,7 +24,7 @@ v::ip(FILTER_FLAG_NO_PRIV_RANGE)->validate('192.168.0.1'); // false
Version | Description
--------|-------------
0.5.0 | Implemented IP range validatio
0.5.0 | Implemented IP range validation
0.3.9 | Created
***
@ -31,3 +33,5 @@ See also:
- [Domain](Domain.md)
- [MacAddress](MacAddress.md)
- [Tld](Tld.md)
[filter_var()]: https://php.net/filter_var

View file

@ -15,13 +15,17 @@ namespace Respect\Validation\Exceptions;
/**
* @author Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
* @author Danilo Benevides <danilobenevides01@gmail.com>
* @author Henrique Moody <henriquemoody@gmail.com>
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
*/
class IpException extends ValidationException
final class IpException extends ValidationException
{
public const NETWORK_RANGE = 'network_range';
/**
* {@inheritdoc}
*/
public static $defaultTemplates = [
self::MODE_DEFAULT => [
self::STANDARD => '{{name}} must be an IP address',
@ -33,6 +37,9 @@ class IpException extends ValidationException
],
];
/**
* {@inheritdoc}
*/
protected function chooseTemplate(): string
{
if (!$this->getParam('networkRange')) {

View file

@ -14,19 +14,52 @@ declare(strict_types=1);
namespace Respect\Validation\Rules;
use Respect\Validation\Exceptions\ComponentException;
use function bccomp;
use function explode;
use function filter_var;
use function ip2long;
use function is_int;
use function long2ip;
use function mb_strpos;
use function mb_substr_count;
use function sprintf;
use function str_replace;
use function strtr;
/**
* Validates whether the input is a valid IP address.
*
* This validator uses the native filter_var() PHP function.
*
* @author Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
* @author Danilo Benevides <danilobenevides01@gmail.com>
* @author Henrique Moody <henriquemoody@gmail.com>
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
*/
class Ip extends AbstractRule
final class Ip extends AbstractRule
{
public $ipOptions;
/**
* @var int|null
*/
private $ipOptions;
public $range;
public $networkRange;
/**
* @var string|null
*/
private $range;
/**
* @var array|null
*/
private $networkRange;
/**
* Initializes the rule defining the range or options for filter_var().
*
* @param int|string $ipOptions
*
* @throws ComponentException In case the range is invalid
*/
public function __construct($ipOptions = null)
{
if (is_int($ipOptions)) {
@ -42,7 +75,12 @@ class Ip extends AbstractRule
/**
* {@inheritdoc}
*/
public function createRange(): ?string
public function validate($input): bool
{
return $this->verifyAddress($input) && $this->verifyNetwork($input);
}
private function createRange(): ?string
{
if (!$this->networkRange) {
return null;
@ -60,11 +98,11 @@ class Ip extends AbstractRule
return $message;
}
protected function parseRange($input)
private function parseRange(?string $input): ?array
{
if (null === $input || '*' == $input || '*.*.*.*' == $input
|| '0.0.0.0-255.255.255.255' == $input) {
return;
return null;
}
$range = ['min' => null, 'max' => null, 'mask' => null];
@ -90,14 +128,14 @@ class Ip extends AbstractRule
return $range;
}
protected function fillAddress(&$input, $char = '*'): void
private function fillAddress(&$input, $char = '*'): void
{
while (mb_substr_count($input, '.') < 3) {
$input .= '.'.$char;
}
}
protected function parseRangeUsingWildcards($input, &$range): void
private function parseRangeUsingWildcards($input, &$range): void
{
$this->fillAddress($input);
@ -105,7 +143,7 @@ class Ip extends AbstractRule
$range['max'] = str_replace('*', '255', $input);
}
protected function parseRangeUsingCidr($input, &$range): void
private function parseRangeUsingCidr($input, &$range): void
{
$input = explode('/', $input);
$this->fillAddress($input[0], '0');
@ -126,12 +164,7 @@ class Ip extends AbstractRule
$range['mask'] = sprintf('%032b', ip2long(long2ip(~(2 ** (32 - $input[1]) - 1))));
}
public function validate($input): bool
{
return $this->verifyAddress($input) && $this->verifyNetwork($input);
}
protected function verifyAddress($address)
private function verifyAddress($address): bool
{
return (bool) filter_var(
$address,
@ -142,7 +175,7 @@ class Ip extends AbstractRule
);
}
protected function verifyNetwork($input)
private function verifyNetwork($input): bool
{
if (null === $this->networkRange) {
return true;
@ -158,7 +191,7 @@ class Ip extends AbstractRule
&& bccomp($input, sprintf('%u', ip2long($this->networkRange['max']))) <= 0;
}
protected function belongsToSubnet($input)
private function belongsToSubnet($input): bool
{
$range = $this->networkRange;
$min = sprintf('%032b', ip2long($range['min']));

View file

@ -0,0 +1,68 @@
--CREDITS--
Danilo Benevides <danilobenevides01@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
--FILE--
<?php
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\IpException;
use Respect\Validation\Exceptions\NestedValidationException;
use Respect\Validation\Validator as v;
try {
v::ip()->check('257.0.0.1');
} catch (IpException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::not(v::ip())->check('127.0.0.1');
} catch (IpException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::ip('127.0.1.*')->check('127.0.0.1');
} catch (IpException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::not(v::ip('127.0.1.*'))->check('127.0.1.1');
} catch (IpException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::ip()->assert('257.0.0.1');
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
try {
v::not(v::ip())->assert('127.0.0.1');
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
try {
v::ip('127.0.1.*')->assert('127.0.0.1');
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
try {
v::not(v::ip('127.0.1.*'))->assert('127.0.1.1');
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
?>
--EXPECTF--
"257.0.0.1" must be an IP address
"127.0.0.1" must not be an IP address
"127.0.0.1" must be an IP address in the "127.0.1.0-127.0.1.255" range
"127.0.1.1" must not be an IP address in the "127.0.1.0-127.0.1.255" range
- "257.0.0.1" must be an IP address
- "127.0.0.1" must not be an IP address
- "127.0.0.1" must be an IP address in the "127.0.1.0-127.0.1.255" range
- "127.0.1.1" must not be an IP address in the "127.0.1.0-127.0.1.255" range

View file

@ -1,26 +0,0 @@
--CREDITS--
Emmerson Siqueira <emmersonsiqueira@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
--FILE--
<?php
require 'vendor/autoload.php';
use Respect\Validation\Rules\Ip;
$ip = new Ip();
var_dump(
$ip->validate('10.0.0.1'),
$ip->validate('192.168.1.150'),
$ip->validate('127.0.0.1'),
$ip->validate('10,0.0.1'),
$ip->validate(null)
);
?>
--EXPECTF--
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)

View file

@ -1,13 +0,0 @@
--CREDITS--
Emmerson Siqueira <emmersonsiqueira@gmail.com>
--FILE--
<?php
require 'vendor/autoload.php';
use Respect\Validation\Validator as v;
v::ip()->assert('192.168.1.150');
v::ip()->check('10.0.0.1');
v::ip('192.168.0.0-192.168.255.255')->check('192.168.2.6');
?>
--EXPECTF--

View file

@ -1,26 +0,0 @@
--CREDITS--
Emmerson Siqueira <emmersonsiqueira@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
--FILE--
<?php
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\AllOfException;
use Respect\Validation\Exceptions\IpException;
use Respect\Validation\Validator as v;
try {
v::ip()->check('foo');
} catch (IpException $e) {
echo $e->getMessage().PHP_EOL;
}
try {
v::ip()->assert('foo');
} catch (AllOfException $e) {
echo $e->getFullMessage().PHP_EOL;
}
?>
--EXPECTF--
"foo" must be an IP address
- "foo" must be an IP address

View file

@ -1,26 +0,0 @@
--CREDITS--
Emmerson Siqueira <emmersonsiqueira@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
--FILE--
<?php
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\AllOfException;
use Respect\Validation\Exceptions\IpException;
use Respect\Validation\Validator as v;
try {
v::not(v::ip())->check('10.0.0.1');
} catch (IpException $e) {
echo $e->getMessage().PHP_EOL;
}
try {
v::not(v::ip())->assert('10.0.0.1');
} catch (AllOfException $e) {
echo $e->getFullMessage().PHP_EOL;
}
?>
--EXPECTF--
"10.0.0.1" must not be an IP address
- "10.0.0.1" must not be an IP address

View file

@ -1,26 +0,0 @@
--CREDITS--
Emmerson Siqueira <emmersonsiqueira@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
--FILE--
<?php
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\AllOfException;
use Respect\Validation\Exceptions\IpException;
use Respect\Validation\Validator as v;
try {
v::ip('127.0.1.*')->check('127.0.0.1');
} catch (IpException $e) {
echo $e->getMessage().PHP_EOL;
}
try {
v::ip('127.0.1.*')->assert('127.0.0.1');
} catch (AllOfException $e) {
echo $e->getFullMessage().PHP_EOL;
}
?>
--EXPECTF--
"127.0.0.1" must be an IP address in the "127.0.1.0-127.0.1.255" range
- "127.0.0.1" must be an IP address in the "127.0.1.0-127.0.1.255" range

View file

@ -1,18 +0,0 @@
--CREDITS--
Emmerson Siqueira <emmersonsiqueira@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
--FILE--
<?php
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Rules\Ip;
try {
$ip = new Ip('192.168');
} catch (ComponentException $e) {
echo $e->getMessage();
}
?>
--EXPECTF--
Invalid network range

View file

@ -13,141 +13,78 @@ declare(strict_types=1);
namespace Respect\Validation\Rules;
use Respect\Validation\Test\TestCase;
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Test\RuleTestCase;
/**
* @group rule
* @covers \Respect\Validation\Exceptions\IpException
* @group rule
*
* @covers \Respect\Validation\Rules\Ip
*
* @author Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
* @author Danilo Benevides <danilobenevides01@gmail.com>
* @author Gabriel Caruso <carusogabriel34@gmail.com>
* @author Henrique Moody <henriquemoody@gmail.com>
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
*/
class IpTest extends TestCase
final class IpTest extends RuleTestCase
{
/**
* @dataProvider providerForIp
* @throws ComponentException
*
* @test
* {@inheritdoc}
*/
public function validIpsShouldReturnTrue($input, $options = null): void
{
$ipValidator = new Ip($options);
self::assertTrue($ipValidator->__invoke($input));
$ipValidator->assert($input);
$ipValidator->check($input);
}
/**
* @dataProvider providerForIpBetweenRange
*
* @test
*/
public function ipsBetweenRangeShouldReturnTrue($input, $networkRange): void
{
$ipValidator = new Ip($networkRange);
self::assertTrue($ipValidator->__invoke($input));
$ipValidator->assert($input);
$ipValidator->check($input);
}
/**
* @dataProvider providerForNotIp
* @expectedException \Respect\Validation\Exceptions\IpException
*
* @test
*/
public function invalidIpsShouldThrowIpException($input, $options = null): void
{
$ipValidator = new Ip($options);
self::assertFalse($ipValidator->__invoke($input));
$ipValidator->assert($input);
}
/**
* @dataProvider providerForIpOutsideRange
* @expectedException \Respect\Validation\Exceptions\IpException
*
* @test
*/
public function ipsOutsideRangeShouldReturnFalse($input, $networkRange): void
{
$ipValidator = new Ip($networkRange);
self::assertFalse($ipValidator->__invoke($input));
$ipValidator->assert($input);
}
public function providerForIp()
public function providerForValidInput(): array
{
return [
['127.0.0.1'],
];
}
public function providerForIpBetweenRange()
{
return [
['127.0.0.1', '127.*'],
['127.0.0.1', '127.0.*'],
['127.0.0.1', '127.0.0.*'],
['192.168.2.6', '192.168.*.6'],
['192.168.2.6', '192.*.2.6'],
['10.168.2.6', '*.168.2.6'],
['192.168.2.6', '192.168.*.*'],
['192.10.2.6', '192.*.*.*'],
['192.168.255.156', '*'],
['192.168.255.156', '*.*.*.*'],
['127.0.0.1', '127.0.0.0-127.0.0.255'],
['192.168.2.6', '192.168.0.0-192.168.255.255'],
['192.10.2.6', '192.0.0.0-192.255.255.255'],
['192.168.255.156', '0.0.0.0-255.255.255.255'],
['220.78.173.2', '220.78.168/21'],
['220.78.173.2', '220.78.168.0/21'],
['220.78.173.2', '220.78.168.0/255.255.248.0'],
];
}
public function providerForNotIp()
{
return [
[''],
[null],
['j'],
[' '],
['Foo'],
['192.168.0.1', FILTER_FLAG_NO_PRIV_RANGE],
];
}
public function providerForIpOutsideRange()
{
return [
['127.0.0.1', '127.0.1.*'],
['192.168.2.6', '192.163.*.*'],
['192.10.2.6', '193.*.*.*'],
['127.0.0.1', '127.0.1.0-127.0.1.255'],
['192.168.2.6', '192.163.0.0-192.163.255.255'],
['192.10.2.6', '193.168.0.0-193.255.255.255'],
['220.78.176.1', '220.78.168/21'],
['220.78.176.2', '220.78.168.0/21'],
['220.78.176.3', '220.78.168.0/255.255.248.0'],
[new Ip('127.*'), '127.0.0.1'],
[new Ip('127.0.*'), '127.0.0.1'],
[new Ip('127.0.0.*'), '127.0.0.1'],
[new Ip('192.168.*.6'), '192.168.2.6'],
[new Ip('192.*.2.6'), '192.168.2.6'],
[new Ip('*.168.2.6'), '10.168.2.6'],
[new Ip('192.168.*.*'), '192.168.2.6'],
[new Ip('192.*.*.*'), '192.168.2.6'],
[new Ip('*'), '192.168.255.156'],
[new Ip('*.*.*.*'), '192.168.255.156'],
[new Ip('127.0.0.0-127.0.0.255'), '127.0.0.1'],
[new Ip('192.168.0.0-192.168.255.255'), '192.168.2.6'],
[new Ip('192.0.0.0-192.255.255.255'), '192.168.2.6'],
[new Ip('0.0.0.0-255.255.255.255'), '192.168.2.6'],
[new Ip('220.78.168/21'), '220.78.173.2'],
[new Ip('220.78.168.0/21'), '220.78.173.2'],
[new Ip('220.78.168.0/255.255.248.0'), '220.78.173.2'],
];
}
/**
* @dataProvider providerForInvalidRanges
* @expectedException \Respect\Validation\Exceptions\ComponentException
* @throws ComponentException
*
* @test
* {@inheritdoc}
*/
public function invalidRangeShouldRaiseException($range): void
public function providerForInvalidInput(): array
{
$o = new Ip($range);
return [
[new Ip('127.*'), '192.0.1.0'],
[new Ip(), ''],
[new Ip(), null],
[new Ip(), 'j'],
[new Ip(), ' '],
[new Ip(), 'Foo'],
[new Ip(FILTER_FLAG_NO_PRIV_RANGE), '192.168.0.1'],
[new Ip('127.0.1.*'), '127.0.0.1'],
[new Ip('192.163.*.*'), '192.168.2.6'],
[new Ip('193.*.*.*'), '192.10.2.6'],
[new Ip('127.0.1.0-127.0.1.255'), '127.0.0.1'],
[new Ip('192.163.0.0-192.163.255.255'), '192.168.2.6'],
[new Ip('193.168.0.0-193.255.255.255'), '192.10.2.6'],
[new Ip('220.78.168/21'), '220.78.176.1'],
[new Ip('220.78.168.0/21'), '220.78.176.2'],
[new Ip('220.78.168.0/255.255.248.0'), '220.78.176.3'],
];
}
public function providerForInvalidRanges()
public function providerForInvalidRanges(): array
{
return [
['192.168'],
@ -159,4 +96,20 @@ class IpTest extends TestCase
['192.168.2.0/8.256.256.256'],
];
}
/**
* @test
*
* @dataProvider providerForInvalidRanges
*
* @param string $range
*
* @throws ComponentException
*/
public function invalidRangeShouldRaiseException(string $range): void
{
$this->expectException(ComponentException::class);
new Ip($range);
}
}