IP Address Validation
An IP address is one of an IPv4 address, an IPv6 address, or an IPv4-mapped IPv6 address.
An IPv4 address consists of four groups, separated by dots, each containing a decimal value between 0 and 255. A regular expression check to match for an IPv4 address would be as follows:
// IPv4 address
'/^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?1)){3}$/D'
An IPv6 address consists of eight groups, separated by colons, each containing a hexadecimal value between 0 and FFFF. A regular expression check to match for an IPv6 address would be as follows:
// IPv6 address (full)
'/^([a-f0-9]{1,4})(?>:(?1)){7}$/iD'
In an IPv6 Address, one or more consecutive groups of 0 value can be represented as a double colon; however, this can only occur once. A regular expression check to match for a compressed IPv6 address would be as follows:
// IPv6 address (compressed)
'/^(?!(?:.*[a-f0-9](?>:|$)){8,})(([a-f0-9]{1,4})(?>:(?2)){0,6})?::(?1)?$/iD'
An IPv4-mapped IPv6 address is an IPv6 address with the final two groups represented as an IPv4 address. A regular expression check to match for an IPv4-mapped IPv6 address would be as follows:
// IPv4-mapped IPv6 address (full)
'/^([a-f0-9]{1,4})(?>:(?1)){5}:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?2)){3}$/iD'
In an IPv4-mapped IPv6 address, one or more consecutive groups of 0 value can be represented as a double colon; however, this can only occur once. A regular expression check to match for a compressed IPv4-mapped IPv6 address would be as follows:
// IPv4-mapped IPv6 address (compressed)
'/^(?!(?:.*[a-f0-9]:){6,})(?>([a-f0-9]{1,4})(?>:(?1)){0,4})?::(?>(?1)(?>:(?1)){0,4}:)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?2)){3}$/iD'
By bringing these regexes together we are left with the following which matches for every IP address:
// IP address
'/^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$/iD'
We can then create a function which returns the return value of a (case-insensitive) preg_match on the above regular expression:
function isValidIPAddress($ipAddress)
{
return preg_match('/^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$/iD', $ipAddress);
}
For a class which allows greater control over which type(s) of IP addresses to validate, see below:
<?php
/**
* Squiloople Framework
*
* LICENSE: Feel free to use and redistribute this code.
*
* @author Michael Rushton <michael@squiloople.com>
* @link http://squiloople.com/
* @category Squiloople
* @package Models
* @subpackage Validators
* @version 1.0
* @copyright Copyright © 2010 Michael Rushton
*/
namespace Models\Validators;
/**
* IP Address Validator
*
* Validate IPv4, IPv6, and IPv4-mapped IPv6 addresses
*/
final class IPAddressValidator
{
/**
* The IP address to validate
*
* @access private
* @var string $_ipAddress
*/
private $_ipAddress;
/**
* An IPv4 address is either allowed (true) or not (false)
*
* @access private
* @var bool $_ipv6
*/
private $_ipv4 = true;
/**
* An IPv6 address is either allowed (true) or not (false)
*
* @access private
* @var bool $_ipv6
*/
private $_ipv6 = false;
/**
* Set the IP address and allow IPv6 addresses if required
*
* @access public
* @param string $ipAddress
* @param bool $all
*/
public function __construct($ipAddress, $ipv6 = false)
{
// Set the IP address
$this->_ipAddress = $ipAddress;
// Allow IPv6 addresses if required
if ($ipv6)
{
$this->setIPv6();
}
}
/**
* Call the constructor fluently
*
* @access public
* @static
* @param string $ipAddress
* @param bool $ipv6
* @return \Models\Validators\IPAddressValidator
*/
public static function setIPAddress($ipAddress, $ipv6 = false)
{
return new self($ipAddress, $ipv6);
}
/**
* Either allow (true) or disallow (false) IPv4 addresses
*
* @access public
* @param bool $allow
* @return \Models\Validators\IPAddressValidator
*/
public function setIPv4($allow = true)
{
// Either allow (true) or disallow (false) an IPv4 address
$this->_ipv4 = $allow;
// Return itself
return $this;
}
/**
* Either allow (true) or disallow (false) IPv6 addresses
*
* @access public
* @param bool $allow
* @return \Models\Validators\IPAddressValidator
*/
public function setIPv6($allow = true)
{
// Either allow (true) or disallow (false) an IPv6 address
$this->_ipv6 = $allow;
// Return itself
return $this;
}
/**
* Return the regular expression for a standard IPv6 address
*
* @access private
* @return string
*/
private function _getIPv6()
{
return '([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?';
}
/**
* Return the regular expression for an IPv4-mapped IPv6 address
*
* @access private
* @return string
*/
private function _getMappedIPv6()
{
return '(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?>(?1)(?>:(?1)){0,4})?::(?>(?1)(?>:(?1)){0,4}:)?';
}
/**
* Return the regular expression for an IPv4 address
*
* @access private
* @return string
*/
private function _getIPv4()
{
return '(?<ip>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?P>ip)){3}';
}
/**
* Establish, and return, the valid format for the IP address
*
* @access private
* @return string
*/
private function _getIPAddress()
{
// The IP address may be either in IPv4 format or in IPv6 format if both are allowed
if ($this->_ipv6 && $this->_ipv4)
{
return '(?>(?>' . $this->_getIPv6() . ')|(?>(?>' . $this->_getMappedIPv6() . ')?' . $this->_getIPv4() . '))';
}
// The IP address may be in IPv6 format if allowed
if ($this->_ipv6)
{
return '(?>(?>' . $this->_getIPv6() . ')|(?>(?>' . $this->_getMappedIPv6() . ')' . $this->_getIPv4() . '))';
}
// Otherwise the IP address must be in IPv4 format
return $this->_getIPv4();
}
/**
* Perform the validation check on the IP address's syntax
*
* @access public
* @return int
*/
public function isValid()
{
return preg_match('/^' . $this->_getIPAddress() . '$/iD', $this->_ipAddress);
}
}
On creating the object, using either \Models\Validators\IPAddressValidator::setIPAddress($ipAddress) or new \Models\Validators\IPAddressValidator($ipAddress), the default settings allow only for IPv4 addresses. If the (optional) second parameter is set to true then IPv6 and IPv4-mapped IPv6 addresses are also allowed. Allowing IPv6 and IPv4-mapped IPv6 addresses can be toggled on and off by calling the setIPv6() method, passing either no parameter or a true parameter to turn it on or a false parameter to turn it off. If IPv6 and IPv4-mapped IPv6 addresses are allowed then IPv4 addresses may be turned off using the setIPv4() method passing false as the parameter. To return the validation check (either 1 if it’s valid or 0 if it’s not), use the isValid() method.
can i have that expression to match ipaddresses (ipv4 and ipv6) in perl?