int n = 0;
while (str < end) {
+ int leading_zero;
if (*str < '0' || *str > '9') {
return 0;
}
+ leading_zero = (*str == '0');
m = 1;
num = ((*(str++)) - '0');
while (str < end && (*str >= '0' && *str <= '9')) {
return 0;
}
}
+ /* don't allow a leading 0; that introduces octal numbers,
+ * which we don't support */
+ if (leading_zero && (num != 0 || m > 1))
+ return 0;
ip[n++] = num;
if (n == 4) {
return str == end;
static int _php_filter_validate_ipv6(char *str, int str_len TSRMLS_DC) /* {{{ */
{
int compressed = 0;
- int blocks = 8;
+ int blocks = 0;
int n;
char *ipv4;
char *end;
if (!_php_filter_validate_ipv4(ipv4, (str_len - (ipv4 - str)), ip4elm)) {
return 0;
}
- str_len = (ipv4 - str) - 1;
- if (str_len == 1) {
- return *str == ':';
+
+ str_len = ipv4 - str; /* length excluding ipv4 */
+ if (str_len < 2) {
+ return 0;
+ }
+
+ if (ipv4[-2] != ':') {
+ /* don't include : before ipv4 unless it's a :: */
+ str_len--;
}
- blocks = 6;
+
+ blocks = 2;
}
end = str + str_len;
while (str < end) {
if (*str == ':') {
- if (--blocks == 0) {
- return 0;
- }
if (++str >= end) {
+ /* cannot end in : without previous : */
return 0;
}
if (*str == ':') {
- if (compressed || --blocks == 0) {
+ if (compressed) {
return 0;
- }
- if (++str == end) {
- return 1;
}
+ blocks++; /* :: means 1 or more 16-bit 0 blocks */
compressed = 1;
+
+ if (++str == end) {
+ return (blocks <= 8);
+ }
} else if ((str - 1) == s) {
+ /* dont allow leading : without another : following */
return 0;
}
}
if (n < 1 || n > 4) {
return 0;
}
+ if (++blocks > 8)
+ return 0;
}
- return (compressed || blocks == 1);
+ return ((compressed && blocks <= 8) || blocks == 8);
}
/* }}} */
--FILE--
<?php
$ipv6_test = array(
- "::127.0.0.1" => true,
- "FF01::101:127.0.1" => false,
- "FF01:0:0:0:101:127.0.1.1" => false,
- "FF01:0:0:0:237:101:127.0.1.1" => true,
- "FF01::101" => true,
- "A1080::8:800:200C:417A" => false,
- "1080::8:Z00:200C:417A" => false,
- "FF01::101::1" => false,
- "1080::8:800:200C:417A" => true,
- "1080:0:0:0:8:800:200C:417A" => true,
+ "::127.0.0.1" => true,
+ "FF01::101:127.0.1" => false,
+ "FF01:0:0:0:101:127.0.1.1" => false,
+ "FF01:0:0:0:237:101:127.0.1.1" => true,
+ "FF01::101" => true,
+ "A1080::8:800:200C:417A" => false,
+ "1080::8:Z00:200C:417A" => false,
+ "FF01::101::1" => false,
+ "1080::8:800:200C:417A" => true,
+ "1080:0:0:0:8:800:200C:417A" => true,
"2001:ec8:1:1:1:1:1:1" => true,
"ffff::FFFF:129.144.52.38" => true,
"::ffff:1.2.3.4" => true,
- "0:0:0:0:0:FFFF:129.144.52.38" => true,
- "0:0:0:0:0:0:13.1.68.3" => true,
- "::13.1.68.3" => true,
- "::FFFF:129.144.52.38" => true,
+ "0:0:0:0:0:FFFF:129.144.52.38" => true,
+ "0:0:0:0:0:0:13.1.68.3" => true,
+ "0:0:0:0:0:0:0:13.1.68.3" => false,
+ "::13.1.68.3" => true,
+ "::FFFF:129.144.52.38" => true,
+
"1:2:3:4:5:6::129.144.52.38" => false,
"::1:2:3:4:5:6:129.144.52.38" => false,
"1:2:3::4:5:6:129.144.52.38" => false,
- "1:2:3:4:5:6:7:8::" => false,
- "::1:2:3:4:5:6:7:8" => false,
+
"1:2:3:4::5:6:7:8" => false,
+ "::1:2:3:4:5:6:7" => true,
+ "::1:2:3:4:5:6:7:8" => false,
+ "1:2:3:4:5:6:7::" => true,
+ "1:2:3:4:5:6:7:8::" => false,
+ "1:2:3:4:5:6:7::8" => false,
+
+ "1:2:3:4:5:6:7:8g" => false,
+ "1:2:3:4:5:6:7:g" => false,
+ "1:2:3:4:5g:6:7:8" => false,
+
+ 'a:b:c:d:e::1.2.3.4' => true,
+ '::0:a:b:c:d:e:f' => true,
+ '0:a:b:c:d:e:f::' => true,
+ ':::1.2.3.4' => false,
+ '8:::1.2.3.4' => false,
+ '::01.02.03.04' => false,
+ '::1.00.3.4' => false,
+ '0:0:0:255.255.255.255' => false,
+ '0:0:0::255.255.255.255' => true,
);
foreach ($ipv6_test as $ip => $exp) {
$out = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
$out = (int) ($out === false ? 0 : 1);
if ($exp != $out) {
- echo "$ip failed\n";
+ echo "$ip failed (expected ", $exp?"true":"false", ", got ",
+ $out?"true":"false", ")\n";
}
}