Trên thực tế, cột số nguyên không dấu đã là cách hiệu quả nhất để tìm kiếm kết quả phù hợp trên một phần địa chỉ ip! Vui lòng không lãng phí năng lượng cũng như thời gian CPU của bạn vào việc chuyển đổi trở lại ký hiệu dạng chấm hoặc tìm kiếm LIKE trên một số loại cột chuỗi.
Có một số cách để viết ra một phần địa chỉ IP, nhưng cuối cùng, tất cả chúng đều chuyển xuống một ip cơ sở với một mặt nạ mạng. Ngoài ra, giả sử một phần, ý bạn là tất cả các IP có tiền tố chung, thì điều này cũng tương đương với việc chỉ định một dải IP.
Dù bằng cách nào, đặc tả địa chỉ IP một phần kết thúc được mô tả dưới dạng hai 32 bit, số nguyên không dấu, được mã hóa theo cùng một định dạng như cột cơ sở dữ liệu của bạn. Bạn có ip bắt đầu và ip kết thúc hoặc bạn có ip cơ sở và mặt nạ. Các số nguyên này có thể được sử dụng trực tiếp bên trong truy vấn SQL của bạn để lấy các kết quả phù hợp một cách hiệu quả. Thậm chí tốt hơn, nếu bạn sử dụng phương pháp tiếp cận phạm vi ip, thì công cụ sẽ có thể tận dụng lợi thế của chỉ mục có thứ tự trên cột ip của bạn. Bạn không thể mong đợi điều gì tốt hơn.
Vậy làm thế nào để xây dựng dải IP? Chúng tôi sẽ phụ thuộc vào cách các địa chỉ một phần của bạn được chỉ định ngay từ đầu, nhưng giả sử rằng bạn biết net mask, thì địa chỉ bắt đầu bằng (base ip &net mask) và địa chỉ kết thúc là ((base ip &net mask) | (~ netmask)), trong đó &, | và ~ tương ứng có nghĩa là theo chiều dọc bit-và, theo chiều ngược kim-hoặc và theo chiều-không-không.
Cập nhật
Đây là mã mẫu để áp dụng chiến lược tôi đã mô tả.
Bây giờ, đã rất lâu kể từ lần cuối tôi viết mã PHP và phần sau chưa bao giờ được thực thi, vì vậy, xin thứ lỗi cho bất kỳ lỗi nào mà tôi có thể đã giới thiệu. Tôi cũng cố tình chọn cách "mở rộng" từng kịch bản ký hiệu để làm cho chúng dễ hiểu hơn thay vì ép tất cả chúng trong một regex rất phức tạp.
if (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [/] (\d{1,2}) $/x', $input, $r)) {
// Four-dotted IP with number of significant bits: 123.45.67.89/24
$a = intval($r[1]);
$b = intval($r[2]);
$c = intval($r[3]);
$d = intval($r[4]);
$mask = intval($r[5]);
} elseif (preg_match(' /^ (\d{1,3}) (?: [.] [*0] [.] [*0] [.] [*0] )? $/x', $input, $r)) {
// Four-dotted IP with three-last numbers missing, or equals to 0 or '*':
// 123.45, 123.45.0.0, 123.45.*.* (assume netmask of 8 bits)
$a = intval($r[1]);
$b = 0;
$c = 0;
$d = 0;
$mask = 8;
} elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) (?: [.] [*0] [.] [*0] )? $/x', $input, $r)) {
// Four-dotted IP with two-last numbers missing, or equals to 0 or '*':
// 123.45, 123.45.0.0, 123.45.*.* (assume netmask of 16 bits)
$a = intval($r[1]);
$b = intval($r[2]);
$c = 0;
$d = 0;
$mask = 16;
} elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) (?: [.] [*0] )? $/x', $input, $r)) {
// Four-dotted IP with last number missing, or equals to 0 or *:
// 123.45.67, 123.45.67.0, 123.45.67.* (assume netmask of 24 bits)
$a = intval($r[1]);
$b = intval($r[2]);
$c = intval($r[3]);
$d = 0;
$mask = 24;
} elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) $/x', $input, $r)) {
// Four-dotted IP: 123.45.67.89 (assume netmask of 32 bits)
$a = intval($r[1]);
$b = intval($r[2]);
$c = intval($r[3]);
$d = intval($r[4]);
$mask = 32;
} else {
throw new Exception('...');
}
if ($a < 0 || $a > 255) { throw new Exception('...') };
if ($b < 0 || $b > 255) { throw new Exception('...') };
if ($c < 0 || $c > 255) { throw new Exception('...') };
if ($d < 0 || $d > 255) { throw new Exception('...') };
if ($mask < 1 || $mask > 32) { throw new Exception('...') };
$baseip = ($a << 24) + ($b << 16) + ($c << 8) + ($d);
$netmask = (1 << (32 - $mask)) - 1;
$startip = $baseip & netmask;
$endip = ($baseip & netmask) | (~netmask);
// ...
doSql( "SELECT ... FROM ... WHERE ipaddress >= ? && ipaddress <= ?", $startip, $endip);
// or
doSql( "SELECT ... FROM ... WHERE ((ipaddress & ?) = ?)", $netmask, $startip);