Page 1 of 1

IP Address Validation

Posted: Sat Jan 23, 2010 1:42 pm
by MichaelR
Checks for IPv4, IPv6, and IPv4-mapped IPv6 addresses:

Code: Select all

  function is_ip_address($ip_address) {

    return preg_match('/^(?:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9](?::|$)){8,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,6})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,6})?))|(?:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){6,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,4})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,4}:)?))?(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))$/i', $ip_address);

  }
 
Or, as a class:

Code: Select all

  /*
   * Copyright © Michael Rushton 2010
   * http://squiloople.com/
   * Feel free to use and redistribute this code. But please keep this copyright notice.
   */

  final class IPAddressValidator {

    private $ip_address;

    private $ipv4   = true;
    private $ipv6   = true;
    private $ipv6v4 = true;

    private function __construct($ip_address, $strict) {

      $this->ip_address = $ip_address;

      if ($strict) {
        $this->SetStrict();
      }

    }

    public static function SetIPAddress($ip_address, $strict = false) {
      return new self($ip_address, $strict);
    }

    public function SetStrict($strict = true) {

      $this->SetIPv4();
      $this->SetIPv6(!$strict);
      $this->SetIPv6v4(!$strict);

      return $this;

    }

    public function SetIPv4($allow = true) {

      $this->ipv4 = $allow;

      return $this;

    }

    public function SetIPv6($allow = true) {

      $this->ipv6 = $allow;

      return $this;

    }

    public function SetIPv6v4($allow = true) {

      $this->ipv6v4 = $allow;

      return $this;

    }

    public function Validate() {

      $ipv6_full       = '[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7}';

      $ipv6_comp       = '(?!(?:.*[a-f0-9](?::|$)){8,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,6})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,6})?';

      $ipv6            = '(?:' . $ipv6_full . ')|(?:' . $ipv6_comp . ')';

      $ipv6v4_full     = '[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:';

      $ipv6v4_comp     = '(?!(?:.*[a-f0-9]:){6,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,4})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,4}:)?';

      $ipv6v4          = '(?:' . $ipv6v4_full . ')|(?:' . $ipv6v4_comp . ')';

      $ipv4            = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}';

      switch (true) {

        case ($this->ipv4 && $this->ipv6 && $this->ipv6v4):
          $ip = '(?:(?:' . $ipv6 . ')|(?:(?:' . $ipv6v4 . ')?' . $ipv4 . '))';
          break;
        case ($this->ipv4 && $this->ipv6):
          $ip = '(?:(?:' . $ipv6 . ')|(?:' . $ipv4 . '))';
          break;
        case ($this->ipv4 && $this->ipv6v4):
          $ip = '(?:' . $ipv6v4 . ')?' . $ipv4;
          break;
        case ($this->ipv6 && $this->ipv6v4):
          $ip = '(?:(?:' . $ipv6 . ')|(?:(?:' . $ipv6v4 . ')' . $ipv4 . '))';
          break;
        case ($this->ipv6):
          $ip = $ipv6;
          break;
        case ($this->ipv6v4):
          $ip = '(?:' . $ipv6v4 . ')' . $ipv4;
          break;
        default:
          $ip = $ipv4;

      }

      return preg_match('/^' . $ip . '$/i', $this->ip_address);

    }

  }

Re: IP Address Validation

Posted: Sat Jan 23, 2010 3:55 pm
by AbraCadaver
Nice work, however I normally use:

Code: Select all

// v4 or v6
filter_var($ip, FILTER_VALIDATE_IP);
 
// v4 only
filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
 
// v6 only
filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);

Re: IP Address Validation

Posted: Sun Jan 24, 2010 7:10 am
by MichaelR
Heh. I didn't know about that. 8O

Thanks. :D

Re: IP Address Validation

Posted: Sun Jan 24, 2010 7:42 am
by MichaelR
There is a problem with that function, though:

Code: Select all

 
filter_var('FFFF::255.255.255.255', FILTER_VALIDATE_IP);
 
// Returns false
 
filter_var('FFFF:::255.255.255.255', FILTER_VALIDATE_IP);
 
// Returns true
 
This is wrong. As per RFC 5321, the correct syntax of a compressed IPv6v4 address is:

Code: Select all

[IPv6-hex *3(":" IPv6-hex)] "::" [IPv6-hex *3(":" IPv6-hex) ":"] IPv4-address-literal
Three consecutive colons are not allowed.

Re: IP Address Validation

Posted: Sun Jan 24, 2010 9:19 am
by AbraCadaver
MichaelR wrote:There is a problem with that function, though:

Code: Select all

 
filter_var('FFFF::255.255.255.255', FILTER_VALIDATE_IP);
 
// Returns false
 
filter_var('FFFF:::255.255.255.255', FILTER_VALIDATE_IP);
 
// Returns true
 
This is wrong. As per RFC 5321, the correct syntax of a compressed IPv6v4 address is:

Code: Select all

[IPv6-hex *3(":" IPv6-hex)] "::" [IPv6-hex *3(":" IPv6-hex) ":"] IPv4-address-literal
Three consecutive colons are not allowed.
Submit it as a bug.

Re: IP Address Validation

Posted: Fri Jan 29, 2010 8:02 pm
by n1tr0b
Well.. I just stumbled upon a cool code... I tested it on Vista... and works like a charm.. and I think I use AbraCadaver's code

Re: IP Address Validation

Posted: Fri Jan 29, 2010 9:40 pm
by AbraCadaver
MichaelR, did you submit a bug report? If it truly is a bug then as PHP users we need to help out and alert the core team to bugs.

Re: IP Address Validation

Posted: Sat Jan 30, 2010 9:25 am
by MichaelR
Yeah, it's here.