mirror of
https://github.com/Respect/Validation.git
synced 2024-06-08 16:52:16 +02:00
Implemented IP range validation (#95)
This commit is contained in:
parent
8355f4bc9d
commit
86f91ad978
|
@ -2,22 +2,119 @@
|
|||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
class Ip extends AbstractRule
|
||||
{
|
||||
|
||||
public $ipOptions;
|
||||
|
||||
public $networkRange;
|
||||
|
||||
public function __construct($ipOptions=null)
|
||||
{
|
||||
$this->ipOptions = $ipOptions;
|
||||
if (is_int($ipOptions)) {
|
||||
$this->ipOptions = $ipOptions;
|
||||
return ;
|
||||
}
|
||||
|
||||
$this->networkRange = $this->parseRange($ipOptions);
|
||||
}
|
||||
|
||||
protected function parseRange($input)
|
||||
{
|
||||
if ($input === null || $input == '*' || $input == '*.*.*.*'
|
||||
|| $input == '0.0.0.0-255.255.255.255')
|
||||
return null;
|
||||
|
||||
$range = array('min' => null, 'max' => null);
|
||||
|
||||
if (strpos($input, '-') !== false)
|
||||
list($range['min'], $range['max']) = explode('-', $input);
|
||||
elseif (strpos($input, '*') !== false) {
|
||||
$this->parseRangeUsingWildcards($input, $range);
|
||||
} elseif (strpos($input, '/') !== false) {
|
||||
$this->parseRangeUsingCidr($input, $range);
|
||||
} else
|
||||
throw new ComponentException('Invalid network range');
|
||||
|
||||
if (!$this->verifyAddress($range['min'])) {
|
||||
throw new ComponentException('Invalid network range');
|
||||
}
|
||||
|
||||
if (isset($range['max']) && !$this->verifyAddress($range['max'])) {
|
||||
throw new ComponentException('Invalid network range');
|
||||
}
|
||||
|
||||
return $range;
|
||||
}
|
||||
|
||||
protected function fillAddress(&$input, $char = '*')
|
||||
{
|
||||
while (substr_count($input, '.') < 3) {
|
||||
$input .= '.' . $char;
|
||||
}
|
||||
}
|
||||
|
||||
protected function parseRangeUsingWildcards($input, &$range)
|
||||
{
|
||||
$this->fillAddress($input);
|
||||
|
||||
$range['min'] = strtr($input, '*', '0');
|
||||
$range['max'] = str_replace('*', '255', $input);
|
||||
}
|
||||
|
||||
protected function parseRangeUsingCidr($input, &$range)
|
||||
{
|
||||
$input = explode('/', $input);
|
||||
$this->fillAddress($input[0], '0');
|
||||
|
||||
$range['min'] = $input[0];
|
||||
$isAddressMask = strpos($input[1], '.') !== false;
|
||||
|
||||
if ($isAddressMask && $this->verifyAddress($input[1])) {
|
||||
$range['mask'] = ip2long($input[1]);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
if ($isAddressMask || $input[1] < 8 || $input[1] > 30) {
|
||||
throw new ComponentException('Invalid network mask');
|
||||
}
|
||||
|
||||
$range['mask'] = ~ (pow(2, (32 - $input[1])) - 1);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
{
|
||||
return $this->verifyAddress($input) && $this->verifyNetwork($input);
|
||||
}
|
||||
|
||||
protected function verifyAddress($address)
|
||||
{
|
||||
return (boolean) filter_var(
|
||||
$input, FILTER_VALIDATE_IP, array('flags' => $this->ipOptions)
|
||||
$address,
|
||||
FILTER_VALIDATE_IP,
|
||||
array(
|
||||
'flags' => $this->ipOptions
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
protected function verifyNetwork($input)
|
||||
{
|
||||
if ($this->networkRange === null)
|
||||
return true;
|
||||
|
||||
$input = ip2long($input);
|
||||
$range = $this->networkRange;
|
||||
|
||||
if (isset($range['mask'])) {
|
||||
return ($input & $range['mask']) == (ip2long($range['min']) & $range['mask']);
|
||||
}
|
||||
|
||||
return $input >= ip2long($range['min'])
|
||||
&& $input <= ip2long($range['max']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,24 +4,27 @@ namespace Respect\Validation\Rules;
|
|||
|
||||
class IpTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
protected $ipValidator;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->ipValidator = new Ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerForIp
|
||||
*
|
||||
*/
|
||||
public function test_valid_ips_should_return_True($input, $options=null)
|
||||
{
|
||||
$this->ipValidator->ipOptions = $options;
|
||||
$this->assertTrue($this->ipValidator->validate($input));
|
||||
$this->assertTrue($this->ipValidator->assert($input));
|
||||
$this->assertTrue($this->ipValidator->check($input));
|
||||
$ipValidator = new Ip($options);
|
||||
$this->assertTrue($ipValidator->validate($input));
|
||||
$this->assertTrue($ipValidator->assert($input));
|
||||
$this->assertTrue($ipValidator->check($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerForIpBetweenRange
|
||||
*/
|
||||
public function test_ips_between_range_should_return_True($input, $networkRange)
|
||||
{
|
||||
$ipValidator = new Ip($networkRange);
|
||||
$this->assertTrue($ipValidator->validate($input));
|
||||
$this->assertTrue($ipValidator->assert($input));
|
||||
$this->assertTrue($ipValidator->check($input));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,9 +33,20 @@ class IpTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function test_invalid_ips_should_throw_IpException($input, $options=null)
|
||||
{
|
||||
$this->ipValidator->ipOptions = $options;
|
||||
$this->assertFalse($this->ipValidator->validate($input));
|
||||
$this->assertFalse($this->ipValidator->assert($input));
|
||||
$ipValidator = new Ip($options);
|
||||
$this->assertFalse($ipValidator->validate($input));
|
||||
$this->assertFalse($ipValidator->assert($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerForIpOutsideRange
|
||||
* @expectedException Respect\Validation\Exceptions\IpException
|
||||
*/
|
||||
public function test_ips_outside_range_should_return_False($input, $networkRange)
|
||||
{
|
||||
$ipValidator = new Ip($networkRange);
|
||||
$this->assertFalse($ipValidator->validate($input));
|
||||
$this->assertFalse($ipValidator->assert($input));
|
||||
}
|
||||
|
||||
public function providerForIp()
|
||||
|
@ -42,6 +56,28 @@ class IpTest extends \PHPUnit_Framework_TestCase
|
|||
);
|
||||
}
|
||||
|
||||
public function providerForIpBetweenRange()
|
||||
{
|
||||
return array(
|
||||
array('127.0.0.1', '127.*'),
|
||||
array('127.0.0.1', '127.0.*'),
|
||||
array('127.0.0.1', '127.0.0.*'),
|
||||
array('192.168.2.6', '192.168.*.6'),
|
||||
array('192.168.2.6', '192.*.2.6'),
|
||||
array('10.168.2.6', '*.168.2.6'),
|
||||
array('192.168.2.6', '192.168.*.*'),
|
||||
array('192.10.2.6', '192.*.*.*'),
|
||||
array('192.168.255.156', '*'),
|
||||
array('192.168.255.156', '*.*.*.*'),
|
||||
array('127.0.0.1', '127.0.0.0-127.0.0.255'),
|
||||
array('192.168.2.6', '192.168.0.0-192.168.255.255'),
|
||||
array('192.10.2.6', '192.0.0.0-192.255.255.255'),
|
||||
array('192.168.255.156', '0.0.0.0-255.255.255.255'),
|
||||
array('220.78.173.2', '220.78.168/21'),
|
||||
array('220.78.173.2', '220.78.168.0/21'),
|
||||
);
|
||||
}
|
||||
|
||||
public function providerForNotIp()
|
||||
{
|
||||
return array(
|
||||
|
@ -54,4 +90,40 @@ class IpTest extends \PHPUnit_Framework_TestCase
|
|||
);
|
||||
}
|
||||
|
||||
public function providerForIpOutsideRange()
|
||||
{
|
||||
return array(
|
||||
array('127.0.0.1', '127.0.1.*'),
|
||||
array('192.168.2.6', '192.163.*.*'),
|
||||
array('192.10.2.6', '193.*.*.*'),
|
||||
array('127.0.0.1', '127.0.1.0-127.0.1.255'),
|
||||
array('192.168.2.6', '192.163.0.0-192.163.255.255'),
|
||||
array('192.10.2.6', '193.168.0.0-193.255.255.255'),
|
||||
array('220.78.176.1', '220.78.168/21'),
|
||||
array('220.78.176.2', '220.78.168.0/21'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerForInvalidRanges
|
||||
* @expectedException Respect\Validation\Exceptions\ComponentException
|
||||
*/
|
||||
public function test_invalid_range_should_raise_exception($range)
|
||||
{
|
||||
$o = new Ip($range);
|
||||
}
|
||||
|
||||
public function providerForInvalidRanges()
|
||||
{
|
||||
return array(
|
||||
array('192.168'),
|
||||
array('asd'),
|
||||
array('192.168.0.0-192.168.0.256'),
|
||||
array('192.168.0.0-192.168.0.1/4'),
|
||||
array('192.168.0/1'),
|
||||
array('192.168.2.0/256.256.256.256'),
|
||||
array('192.168.2.0/8.256.256.256'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue