这种方法起初似乎很有效,但我很快发现,当我将任何以.32结尾的IP与较低的IP地址进行比较时,结果是不正确的。例如,如果我将192.168.1.0与192.168.1.32进行比较,我的脚本告诉我192.168.1.0大于192.168.1.32。这仅发生在其中一个IP以.32结尾时。IP的前三个八位组可以更改,结果相同。
The following PHP code generates a page that illustrates this issue:
// Loop through every possible last octet, starting with zero
for ($i = 0; $i <= 255; $i++) {
// Define two IPs, with second IP increasing on each loop by 1
$IP1 = "192.168.1.0";
$IP2 = "192.168.1.".$i;
// Convert each IP to a binary string
$IP1_bin = current(unpack("A4",inet_pton($IP1)));
$IP2_bin = current(unpack("A4",inet_pton($IP2)));
// Convert each IP back to human readable format, just to show they were converted properly
$IP1_string = inet_ntop(pack("A4",$IP1_bin));
$IP2_string = inet_ntop(pack("A4",$IP2_bin));
// Compare each IP and echo the result
if ($IP1_bin < $IP2_bin) {echo '<p>'.$IP1_string.' is LESS than '.$IP2_string.'</p>';}
if ($IP1_bin === $IP2_bin) {echo '<p>'.$IP1_string.' is EQUAL to '.$IP2_string.'</p>';}
if ($IP1_bin > $IP2_bin) {echo '<p>'.$IP1_string.' is GREATER than '.$IP2_string.'</p>';}
// I have also tried using strcmp for the binary comparison, with the same result
// if (strcmp($IP1_bin,$IP2_bin) < 0) {echo '<p>'.$IP1_string.' is LESS than '.$IP2_string.'</p>';}
// if (strcmp($IP1_bin,$IP2_bin) === 0) {echo '<p>'.$IP1_string.' iS EQUAL to '.$IP2_string.'</p>';}
// if (strcmp($IP1_bin,$IP2_bin) > 0) {echo '<p>'.$IP1_string.' is GREATER than '.$IP2_string.'</p>';}
}
?>
Here is a sample of the result:
192.168.1.0 is EQUAL to 192.168.1.0
192.168.1.0 is LESS than 192.168.1.1
192.168.1.0 is LESS than 192.168.1.2
192.168.1.0 is LESS than 192.168.1.3
192.168.1.0 is LESS than 192.168.1.4
...
192.168.1.0 is LESS than 192.168.1.31
192.168.1.0 is GREATER than 192.168.1.32
192.168.1.0 is LESS than 192.168.1.33
...
Converting the IPs back to human readable format returns the correct IP, so I believe the issue is with the comparison. I have tried switching to strcmp for the binary comparison, however the result was the same.
Any help in determining the cause of this would be greatly appreciated. I am not set on using the IP conversion and comparison methods shown in the example script, however I do need to stick with methods that support both IPv4 and IPv6. Thanks.
I am running PHP verison 5.3.3, with Zend Engine v2.3.0 and ionCube PHP Loader v4.6.1
Edit: I resolved the issue by changing the unpack format from "A4" (space-padded strings) to "a4" (NUL-padded strings). See my answer below for details.