During researches for a regex that matches an IP address accurately I found this article which is the first result on google. The article shows a regular expression for accurate matching but it is not correct: It doesn’t respect, that a leading zero in a component of the IP marks that the component should be interpreted as an octal number.
For example it matches:
1.095.1.1
as a valid IP. But 95
isn’t a valid octal number!
Knowing this, I started to craft my own regex which should respect this. In it’s first version it will simply reject octal numbers as component. This lead me to the following pattern:
<?php
$pattern = '/^((^|\.)(1[0-9]{2}|[1-9][0-9]|[0-9]|2[0-4][0-9]|25[0-5])){4}$/';
The pattern works a bit different than the regex shown in that article, while the article defines an IP addess as a series of 3 numbers followed by a dot .
plus another number, this pattern defines the IP address as a series of 4 numbers which are optionally preceded by a dot .
or the start of the string. This makes the regex pattern itself much shorter and simpler.
Explanation:
The regex requires that each part of the IP will start with a dot .
or the beginning of the string ^
(which is true for the first component):
(^|\.)
Each component needs to be in one of the following ranges:
1[0-9]{2}
range: 100 – 199[1-9][0-9]
range: 10 – 99[0-9]
range: 0 – 92[0-4][0-9]
range: 200 – 24925[0-5]
range: 250 – 255
Test:
The following scripts tests if the regex matches valid IP addresses and rejects invalid ones:
<?php
$pattern = '/^((^|\.)(1[0-9]{2}|[1-9][0-9]|[0-9]|2[0-4][0-9]|25[0-5])){4}$/';
foreach(array(
'10.23.34.2',
'0.0.0.0',
'127.0.0.1',
'255.255.255.0',
'192.168.0.1',
'1.1.1.1'
) as $ip) {
if(!preg_match($pattern, $ip, $m)) {
echo "$ip FAILED\n";
}
}
foreach(array(
'10.23.343.2',
'0.0.0',
'127.0.0.1.2',
'test',
'256.256.34.5',
'10.01.02.3'
) as $ip) {
if(preg_match($pattern, $ip, $m)) {
echo "$ip FALSE POSITIVE\n";
}
}
Leave a Reply