10.0.%.1 のように、ワイルドカードを含む IP アドレスを保存する必要があります。次に、許可された範囲 (10.0.0-255.1) 内の IP アドレスを持つ人がクエリから見つかるようにします。
皆さん、私を助けてくれませんか? 10.0.%.1 を保存しようとしましたが、LIKE クエリでそれを見つけることができません (それがその方法であるかどうかさえわかりません - おそらくそうではありません)。
前もって感謝します。
IP アドレスを 32 ビット整数に変換し、アドレスとマスクの列を作成します。INET_NTOA()
およびINET_ATON()
機能を使用できます。10.0.%.1 の範囲は、255.255.0.255 のマスクを持つネットワーク 10.0.0.1 として表すことができます。特定の IP アドレスがこのネットワークと一致するかどうかを確認するには、マスクを IP アドレスに適用し、それをネットワーク アドレスと比較します。それらが一致する場合、アドレスはネットワーク内にあります。たとえば、10.0.4.1 をテストする場合は、ビットごとの AND を使用してマスクを適用します。
10.0.4.1 & 255.255.0.255 = 10.0.0.1
これはネットワーク アドレスと一致するため、この IP はネットワーク内にあります。
このネットワークを次のようにテーブルに保存できます (ip と mask は整数です)。
CREATE TABLE networks (id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, ip INT, mask INT);
INSERT INTO networks (ip, mask)
VALUES (INET_ATON('10.0.0.1'), INET_ATON('255.255.0.255'));
特定の IP (10.0.23.1) が次のように一致するかどうかを確認できます。
SELECT * FROM networks
WHERE ip & mask = INET_ATON('10.0.23.1') & mask
ただし、人間が判読できるようにする場合は、これにより IP が整数として選択されます。
SELECT id, INET_NTOA(ip) AS ipstring, INET_NTOA(mask) AS maskstring
FROM networks
WHERE ip & mask = INET_ATON('10.0.23.1') & mask
これにより、特定の 1 つの IP アドレスがネットワークと一致するかどうかをテストできます。IP の範囲をテストする場合は、範囲内の各 IP にマスクを適用し、上記のようにそれぞれをテストする必要があります。単一のクエリで実行できます。テストするすべての IP アドレスをリストするだけです。
次のように、IP アドレスを 4 つの整数としてデータベースに保存します。
IPpart1 IPpart2 IPpart3 IPpart4
-------------------------------
127 0 0 1
そしてそれらをヌル可能にします。(NULL がワイルドカードになります)
次に、次のようにデータベースに対してクエリを実行できます。
SELECT * FROM iptable WHERE (IPpart1 IS NULL OR IPpart1 = '$firstpart') AND (IPpart2 IS NULL OR IPpart2 = '$secondpart') AND (IPpart3 IS NULL OR IPpart3 = '$thirdpart') AND (IPpart4 IS NULL OR IPpart4 = '$fourthpart')
それは仕事を成し遂げる少し冗長なビットです。
通常の IP フィールドからその構造を使用して一時テーブルを作成することも可能ですが、多くのリクエストがある場合はオーバーヘッドが大きくなります。
MySQL のドキュメント ページを詳しく調べたところ、ニーズに合った投稿が見つかりました。
SELECT '10.0.0.1' AS IP0,
( SUBSTRING_INDEX( '10.0.0.1', '.', 1 ) * 16777216 +
SUBSTRING_INDEX(SUBSTRING_INDEX( '10.0.0.1', '.', 2 ),'.',-1) * 65536 +
SUBSTRING_INDEX(SUBSTRING_INDEX( '10.0.0.1', '.', -2 ),'.',1) * 256 +
SUBSTRING_INDEX( '10.0.0.1', '.', -1 )
),
'10.0.255.1' AS IP1,
( SUBSTRING_INDEX( '10.0.255.1', '.', 1 ) * 16777216 +
SUBSTRING_INDEX(SUBSTRING_INDEX( '10.0.255.1', '.', 2 ),'.',-1) * 65536 +
SUBSTRING_INDEX(SUBSTRING_INDEX( '10.0.255.1', '.', -2 ),'.',1) * 256 +
SUBSTRING_INDEX( '10.0.255.1', '.', -1 )
) AS IP2Num1
各 IP の数値を返します。
Ip: | 10.0.0.1 | 10.0.255.1 |
--------------------------------
Num: | 167772161 | 167837441 |
言い換えると:
SELECT foo
FROM bar.foobar
WHERE ( SUBSTRING_INDEX( ipField, '.', 1 ) * 16777216 +
SUBSTRING_INDEX(SUBSTRING_INDEX( ipField, '.', 2 ),'.',-1) * 65536 +
SUBSTRING_INDEX(SUBSTRING_INDEX( ipField, '.', -2 ),'.',1) * 256 +
SUBSTRING_INDEX( ipField, '.', -1 )
) BETWEEN 167772161 AND 167837441;
さて、あなたはこれを行うことができます:
WHERE ipField LIKE '10.0.%.1'
AND (CAST
(REPLACE(SUBSTRING_INDEX(ipField,'.',3),
CONCAT(SUBSTRING_INDEX(ipField ,'.',2),'.')
,'')
AS UNSIGNED) BETWEEN 0 AND 255)
次のクエリでテストしました:
SELECT IF ('10.0.12.1' LIKE '10.0.%.1'
AND (CAST
(REPLACE( SUBSTRING_INDEX('10.0.12.1','.',3),
CONCAT(SUBSTRING_INDEX('10.0.12.1','.',2),'.')
,'')
AS UNSIGNED) BETWEEN 0 AND 255),
TRUE,
FALSE);
そしてそれは を返します1
が、正直なところ、それは少しばかげていますね。なぜ単純ではないのですか:
WHERE ipField REGEXP '10\\.0\\.[0-9]{1,3}\\.1'
この式を少し調整することはできますが、基本的には、これが IP アドレスを照会する最も簡単な方法のように思えます。
MySQL 文字列関数 (ほとんどの場合、記述するのが面倒になります) の詳細については、こちらのドキュメントを参照してください。