Sebenarnya, kolom bilangan bulat yang tidak ditandatangani sudah merupakan cara paling efisien untuk mencari kecocokan pada sebagian alamat ip! Tolong jangan buang energi atau waktu CPU Anda untuk mengubah kembali ke notasi titik-titik atau melakukan pencarian LIKE pada semacam kolom string.
Ada beberapa cara untuk menuliskan alamat IP parsial, tetapi pada akhirnya, semuanya diturunkan ke ip dasar dengan net mask. Juga, dengan asumsi bahwa secara parsial, yang Anda maksud adalah semua IP dengan awalan yang sama, Maka ini juga setara dengan menentukan rentang IP.
Either way, spesifikasi alamat IP parsial akhirnya digambarkan sebagai dua 32 bit, bilangan bulat yang tidak ditandatangani, dikodekan dalam format yang sama dengan kolom database Anda. Entah Anda memiliki ip awal dan ip akhir, atau Anda memiliki ip dasar dan topeng. Bilangan bulat ini dapat digunakan langsung di dalam kueri SQL Anda untuk mendapatkan kecocokan secara efisien. Lebih baik lagi, jika Anda menggunakan pendekatan jangkauan ip, maka mesin akan dapat memanfaatkan indeks yang dipesan pada kolom ip Anda. Anda tidak dapat mengharapkan yang lebih baik.
Jadi bagaimana membangun rentang IP? Kami akan itu tergantung bagaimana alamat parsial Anda ditentukan di tempat pertama, tetapi dengan asumsi bahwa Anda tahu topeng bersih, maka alamat awal sama dengan (base ip &net mask), dan alamat akhirnya adalah ((base ip &topeng bersih) | (~netmask)), di mana &, | dan ~ masing-masing berarti bitwise-and, bitwise-or dan bitwise-not.
Perbarui
Berikut adalah contoh kode untuk menerapkan strategi yang saya jelaskan.
Sekarang, sudah sangat lama sejak saya terakhir menulis kode PHP, dan berikut ini belum pernah dieksekusi, jadi mohon maafkan kesalahan yang mungkin saya perkenalkan. Saya juga sengaja memilih untuk "memperluas" setiap skenario notasi agar lebih mudah dipahami, daripada memeras semuanya dalam satu regex yang sangat kompleks.
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);