Dada una matriz de identificadores $galleries = array(1,2,5)
, quiero tener una consulta SQL que use los valores de la matriz en su cláusula WHERE como:
SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */
¿Cómo puedo generar esta cadena de consulta para usar con MySQL?
Respuestas:
fuente
$galleries
debe validarse antes de esta declaración! Las declaraciones preparadas no pueden manejar matrices AFAIK, por lo que si está acostumbrado a variables enlazadas, podría hacer posible la inyección de SQL aquí.$galleries
tenía el valor siguiente:array('1); SELECT password FROM users;/*')
. Si no desinfecta eso, la consulta se leeríaSELECT * FROM galleries WHERE id IN (1); SELECT password FROM users;/*)
. Cambie los nombres de tabla y columna a algo que tenga en su base de datos e intente esa consulta, consulte los resultados. Encontrará una lista de contraseñas como resultado, en lugar de una lista de galerías. Dependiendo de cómo se emiten los datos, o de lo que hace el script con una matriz de datos inesperados, eso podría obtener la salida a la vista pública ... ¡ay!$galleries
que se proporciona en la pregunta y lo explota usando la "vulnerabilidad de inyección sql" mencionada anteriormente. Si no puede, me paga USD200. ¿Qué hay sobre eso?Usando PDO: [1]
Usando MySQLi [2]
Explicación:
Use el
IN()
operador SQL para verificar si existe un valor en una lista dada.En general se ve así:
Podemos construir una expresión para colocar dentro
()
de nuestra matriz. Tenga en cuenta que debe haber al menos un valor dentro del paréntesis o MySQL devolverá un error; esto equivale a asegurarse de que nuestra matriz de entrada tenga al menos un valor. Para ayudar a prevenir ataques de inyección SQL, primero genere un?
para cada elemento de entrada para crear una consulta parametrizada. Aquí supongo que la matriz que contiene sus identificadores se llama$ids
:Dada una matriz de entrada de tres elementos
$select
se verá así:Nuevamente, tenga en cuenta que hay un
?
para cada elemento en la matriz de entrada. Luego usaremos PDO o MySQLi para preparar y ejecutar la consulta como se indicó anteriormente.Usando el
IN()
operador con cuerdasEs fácil cambiar entre cadenas y enteros debido a los parámetros enlazados. Para PDO no se requiere cambio; para MySQLi cambie
str_repeat('i',
astr_repeat('s',
si necesita verificar cadenas.[1]: He omitido alguna comprobación de errores por brevedad. Debe verificar los errores habituales para cada método de base de datos (o configurar su controlador de base de datos para que arroje excepciones).
[2]: Requiere PHP 5.6 o superior. Nuevamente, he omitido algunos errores de comprobación de brevedad.
fuente
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
entonces...
está expandiendo los id de una matriz a múltiples parámetros. Si se refiere aexpr IN (value,...)
eso, eso solo significa que puede haber más valores, por ejemploWHERE id IN (1, 3, 4)
. Solo tiene que haber al menos uno....
: wiki.php.net/rfc/argument_unpackingentradas:
instrumentos de cuerda:
fuente
Suponiendo que desinfecte adecuadamente sus entradas de antemano ...
Luego solo ajusta tu consulta:
Cotice los valores de manera apropiada según su conjunto de datos.
fuente
Utilizar:
Un
for each
bucle simple funcionará.La forma de Flavius / AvatarKava es mejor, pero asegúrese de que ninguno de los valores de la matriz contenga comas.
fuente
Como respuesta de Flavius Stef , puede usar
intval()
para asegurarse de que todosid
sean valores int:fuente
Para MySQLi con una función de escape:
Para PDO con declaración preparada:
fuente
Debemos ocuparnos de las vulnerabilidades de inyección SQL y una condición vacía . Voy a manejar ambos como a continuación.
Para una matriz numérica pura, utilice el viz conversión tipo apropiado
intval
ofloatval
odoubleval
más de cada elemento. Para tipos de cadenamysqli_real_escape_string()
que también pueden aplicarse a valores numéricos si lo desea. MySQL permite números y variantes de fecha como cadena .Para escapar adecuadamente de los valores antes de pasar a la consulta, cree una función similar a:
Es probable que dicha función ya esté disponible en su aplicación, o tal vez ya haya creado una.
Desinfecte el conjunto de cadenas como:
Una matriz numérica puede ser desinfectados utilizando
intval
ofloatval
odoubleval
en lugar como adecuados:Luego, finalmente construya la condición de consulta
o
Dado que la matriz también puede estar vacía a veces, como
$galleries = array();
deberíamos tener en cuenta queIN ()
no permite una lista vacía. También se puede usarOR
, pero el problema persiste. Por lo tanto, la comprobación anteriorcount($values)
es para garantizar lo mismo.Y agréguelo a la consulta final:
fuente
$query = 'SELECT * FROM galleries WHERE ' . (count($gallaries) ? "id IN ('" . implode("', '", array_map('escape', $gallaries)) . "')" : 0);
Más seguro
fuente
La biblioteca SafeMySQL de Col. Shrapnel para PHP proporciona marcadores de posición con sugerencias de tipo en sus consultas parametrizadas e incluye un par de marcadores de posición convenientes para trabajar con matrices. los
?a
marcador de posición expande una matriz a una lista separada por comas de cadenas escapadas *.Por ejemplo:
* Tenga en cuenta que, dado que MySQL realiza una coerción de tipo automática, no importa que SafeMySQL convierta los identificadores anteriores en cadenas; de todos modos, obtendrá el resultado correcto.
fuente
Podemos usar esta cláusula "WHERE id IN" si filtramos la matriz de entrada correctamente. Algo como esto:
Como el siguiente ejemplo:
Es decir, ahora debe usar con seguridad
$query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";
fuente
Puedes tener mesa
texts
(T_ID (int), T_TEXT (text))
y mesatest
(id (int), var (varchar(255)))
A
insert into test values (1, '1,2,3') ;
continuación, se mostrarán filas de los textos de la tabla dondeT_ID IN (1,2,3)
:De esta manera, puede administrar una relación de base de datos n2m simple sin una tabla adicional y usando solo SQL sin la necesidad de usar PHP u otro lenguaje de programación.
fuente
Más un ejemplo:
fuente
Además de usar la consulta IN, tiene dos opciones para hacerlo, ya que en una consulta IN existe el riesgo de una vulnerabilidad de inyección SQL. Puede usar el bucle para obtener los datos exactos que desea o puede usar la consulta con el caso OR
fuente
Forma segura sin PDO:
(array)$ids
Convertir$ids
variable en matrizarray_map
Transforme todos los valores de la matriz en enterosarray_unique
Eliminar valores repetidosarray_filter
Eliminar valores ceroimplode
Unir todos los valores a la selección INfuente
Debido a que la pregunta original se relaciona con un conjunto de números y estoy usando un conjunto de cadenas, no pude hacer que los ejemplos dados funcionen.
Descubrí que cada cadena necesitaba ser encapsulada entre comillas simples para trabajar con la
IN()
función.Aqui esta mi solucion
Como puede ver, la primera función envuelve cada variable de matriz
single quotes (\')
y luego implosiona la matriz.NOTA:
$status
no tiene comillas simples en la instrucción SQL.Probablemente haya una mejor manera de agregar las comillas, pero esto funciona.
fuente
$filter = "'" . implode("','",$status) . "'";
'
dentro de la cadena? Inyección SQL vulnerable. Utilice PDO :: quote o mysqli_real_escape_string.A continuación se muestra el método que he utilizado, utilizando PDO con marcadores de posición con nombre para otros datos. Para superar la inyección SQL, estoy filtrando la matriz para aceptar solo los valores que son enteros y rechazando todos los demás.
fuente
Los métodos básicos para evitar la inyección de SQL son:
El uso de declaraciones preparadas y consultas parametrizadas se considera la mejor práctica, pero si elige el método de caracteres de escape, puede probar mi ejemplo a continuación.
Puede generar las consultas utilizando
array_map
para agregar una comilla simple a cada uno de los elementos en$galleries
:El $ sql var generado será:
fuente