2012-10-01 10 views
5

Necesito almacenar una dirección IP con un comodín, como 10.0.%. 1. Entonces, quiero que cualquier persona con una dirección IP en el rango permitido (10.0.0-255.1) se encuentre desde mi consulta.¿Cómo almaceno (y encuentro) una cadena con un comodín en MySQL?

¿Podrían ayudarme? Intenté almacenar 10.0.%. 1 pero no puedo encontrarlo con una consulta LIKE (ni siquiera sé si esa es la manera de hacerlo, probablemente no).

Gracias de antemano.

+0

¿por qué almacena los valores con%? –

+0

Utilice un número mayor que 255 (como '350') y reemplácelo con un comodín en php? – hjpotter92

+0

¿Cómo quieres usar tu comodín? ¿Sería 10.0.1% .1 y 10.% considerados válidos también? – Josay

Respuesta

2

¿Qué se guarda las direcciones IP como 4 enteros en la base de datos de este modo:

IPpart1 IPpart2 IPpart3 IPpart4 
------------------------------- 
127  0  0  1 

y hacerlos anulable. (NULL va a ser nuestro comodín)

entonces usted puede hacer una consulta en la base de datos de esta manera:

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') 

Es un poco prolijo poco que hace el trabajo.

Incluso debería ser posible construir una tabla temporal con esa estructura a partir de un campo de IP normal, pero sería una gran sobrecarga si tiene muchas solicitudes.

+0

Gracias por el enfoque diferente: esto funcionó muy bien para mí y fue lo suficientemente simple como para configurarlo. –

3

Convierta direcciones IP a enteros de 32 bits y cree una columna para la dirección y la máscara. Puede usar las funciones INET_NTOA() y INET_ATON(). Su rango de 10.0.%. 1 se puede expresar como la red 10.0.0.1 con una máscara de 255.255.0.255. Para ver si una dirección IP determinada coincide con esta red, aplique la máscara a la dirección IP y compárela con la dirección de red. Si coinciden, la dirección está en la red. Por ejemplo, si desea probar 10.0.4.1, aplicar la máscara a él utilizando AND bit a bit:

10.0.4.1 & 255.255.0.255 = 10.0.0.1 

Esto coincide con la dirección de red, por lo que este es IP en la red.

Puede almacenar esta red en su tabla de este modo (IP y la máscara son enteros):

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')); 

Usted puede encontrar si una dirección IP determinada (10.0.23.1) coincide así:

SELECT * FROM networks 
WHERE ip & mask = INET_ATON('10.0.23.1') & mask 

Esto seleccionará los proyectos de investigación como enteros sin embargo, si usted quiere que ellos legible:

SELECT id, INET_NTOA(ip) AS ipstring, INET_NTOA(mask) AS maskstring 
FROM networks 
WHERE ip & mask = INET_ATON('10.0.23.1') & mask 

Esto le permite tE st si una sola dirección IP dada coincide con una red. Si desea probar un rango de direcciones IP, debe aplicar la máscara a cada uno en el rango y probar cada uno como se muestra arriba. Puedes hacerlo en una sola consulta, solo tendrá que listar cada dirección IP que estés probando.

+0

Interesante, ¿es posible consultar un rango de IP como este? digamos rango de '10.0.12.1' a' 10.0.123.2' si usa 'BETWEEN int1 AND int2'? –

+0

No, no puedes hacer eso. Tendría que aplicar la máscara a cada dirección IP en el rango y luego compararla con la dirección de red. Esto se debe a que la máscara de red puede tener agujeros, e incluso si ambos extremos de su rango están en la red, es posible que algunas direcciones en el medio del rango no lo estén. Por ejemplo, si mi máscara fuera 255.255.2.255 para una red 10.0.0.1, las IP 10.0.0.1, 10.0.4.1 y 10.0.5.1 estarían en la red, pero 10.0.2.1 y 10.0.3.1 no. –

+0

¿No funcionaría 'WHERE ip & mask BETWEEN INET_ATOM ('10 .0.20.1 ') & mask AND INET_ATOM ('10 .0.50.1') & mask'? No veo ninguna razón por la que no lo haga. En el peor de los casos, necesitarías una especie de combinación, pero a menos que me esté perdiendo algo, funcionaría, ¿no? –

0

que tenían una mirada más cercana en las páginas doc MySQL, y me encontré un puesto de ahí que se adapte a sus necesidades:

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 

Devuelve un valor numérico para cada IP:

Ip: | 10.0.0.1 | 10.0.255.1 | 
-------------------------------- 
Num: | 167772161 | 167837441 | 

En otra palabras:

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; 

Bueno, podría hace esto:

WHERE ipField LIKE '10.0.%.1' 
AND (CAST 
     (REPLACE(SUBSTRING_INDEX(ipField,'.',3), 
       CONCAT(SUBSTRING_INDEX(ipField ,'.',2),'.') 
       ,'') 
    AS UNSIGNED) BETWEEN 0 AND 255) 

Qué he probado con la siguiente consulta:

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); 

y vuelve 1, pero, honestamente, eso es un poco de un faff, no es ¿eso? ¿Por qué no simplemente:

WHERE ipField REGEXP '10\\.0\\.[0-9]{1,3}\\.1' 

Se pueden ajustar esta expresión un poco, pero básicamente, que me parece ser la forma más sencilla de interrogar a esas direcciones IP.
Para obtener más información sobre las funciones de cadena de MySQL (que casi siempre serán difíciles de escribir), consulte the docs here

+0

En lugar de usar todas las funciones 'SUBSTRING_INDEX()' para convertir una cadena IP en un entero, puede usar 'INET_ATON()'. –

+0

Leí su respuesta después de publicarla y la califiqué. Tal vez OP se pregunte si la implementación de su respuesta requiere que modifique sus tablas y le permite usar 'BETWEEN' para consultar un rango de IP ... quizás usted podría querer editar su respuesta para reflexionar sobre eso. IMO, la tuya es la respuesta, pero he dado algunos enlaces aquí que pueden ser útiles para algunas personas, pero vuelvo a decir: has proporcionado la mejor respuesta a la pregunta en cuestión –

+0

Gracias, actualicé mi respuesta con la tabla esquema y prueba para un rango de IP. –

Cuestiones relacionadas