php - mysql_fetch_all - mysql_fetch_array foreach
Pasar una matriz a una consulta utilizando una cláusula WHERE (18)
Dada una matriz de IDs $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?
¡TENER CUIDADO! Esta respuesta contiene una severa vulnerabilidad de inyección SQL . NO use los ejemplos de código como se presentan aquí, sin asegurarse de que cualquier entrada externa esté desinfectada.
$ids = join("'',''",$galleries);
$sql = "SELECT * FROM galleries WHERE id IN (''$ids'')";
A continuación se muestra el método que he usado, 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 rechazar todos los demás.
$owner_id = 123;
$galleries = array(1,2,5,''abc'');
$good_galleries = array_filter($chapter_arr, ''is_numeric'');
$sql = "SELECT * FROM galleries WHERE owner=:OWNER_ID AND id IN ($good_galleries)";
$stmt = $dbh->prepare($sql);
$stmt->execute(array(
"OWNER_ID" => $owner_id,
));
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
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
1. SELECT *
FROM galleries WHERE id=1 or id=2 or id=5;
2. $ids = array(1, 2, 5);
foreach ($ids as $id) {
$data[] = SELECT *
FROM galleries WHERE id= $id;
}
Como respuesta de Flavius Stef , puedes usar intval()
para asegurarte de que todos los id
sean valores int:
$ids = join('','', array_map(''intval'', $galleries));
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
Debemos cuidar las vulnerabilidades de inyección SQL y una condición vacía . Voy a manejar tanto como a continuación.
Para una matriz numérica pura, use el tipo de conversión de tipo intval
o floatval
o doubleval
sobre cada elemento. Para los tipos de cadena mysqli_real_escape_string()
que también se pueden aplicar 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:
function escape($string)
{
// Assuming $db is a link identifier returned by mysqli_connect() or mysqli_init()
return mysqli_real_escape_string($db, $string);
}
Es probable que esa función ya esté disponible para usted en su aplicación, o tal vez ya haya creado una.
Desinfecte la cadena de cadenas como:
$values = array_map(''escape'', $gallaries);
Una matriz numérica se puede desinfectar utilizando intval
o floatval
o doubleval
en doubleval
lugar, según corresponda:
$values = array_map(''intval'', $gallaries);
Entonces finalmente construir la condición de consulta
$where = count($values) ? "`id` = ''" . implode("'' OR `id` = ''", $values) . "''" : 0;
o
$where = count($values) ? "`id` IN (''" . implode("'', ''", $values) . "'')" : 0;
Dado que la matriz también puede estar vacía a veces, como $galleries = array();
por lo tanto, debemos tener en cuenta que IN ()
no permite una lista vacía. También se puede usar OR
lugar, pero el problema persiste. Así que el cheque anterior, count($values)
, es asegurar lo mismo.
Y añádelo a la consulta final:
$query = ''SELECT * FROM `galleries` WHERE '' . $where;
CONSEJO : si desea mostrar todos los registros (sin filtrado) en caso de una matriz vacía en lugar de ocultar todas las filas, simplemente reemplace 0 por 1 en la parte falsa del ternario.
Debido a que la pregunta original se relaciona con una serie de números y estoy usando una serie de cadenas, no pude hacer que los ejemplos dados funcionen.
Descubrí que cada cadena debía encapsularse en comillas simples para trabajar con la función IN()
.
Aquí está mi solución
foreach($status as $status_a) {
$status_sql[] = ''/'''.$status_a.''/''';
}
$status = implode('','',$status_sql);
$sql = mysql_query("SELECT * FROM table WHERE id IN ($status)");
Como puede ver, la primera función envuelve cada variable de matriz en single quotes (/')
y luego implosiona la matriz.
NOTA: $status
no tiene comillas simples en la declaración SQL.
Probablemente hay una forma mejor de agregar las citas, pero esto funciona.
La biblioteca SafeMySQL Col. Shrapnel para PHP proporciona marcadores de posición de tipo insinuado en sus consultas parametrizadas, e incluye un par de marcadores de posición convenientes para trabajar con arrays. El ?a
marcador de posición expande una matriz a una lista separada por comas de cadenas escapadas *.
Por ejemplo:
$someArray = [1, 2, 5];
$galleries = $db->getAll("SELECT * FROM galleries WHERE id IN (?a)", $someArray);
* Tenga en cuenta que, dado que MySQL realiza una conversión automática de tipos, no importa que SafeMySQL convierta los identificadores anteriores a cadenas, aún obtendrá el resultado correcto.
Los métodos básicos para prevenir la inyección de SQL son:
- Utilizar declaraciones preparadas y consultas parametrizadas.
- Escapar de los caracteres especiales en su variable insegura.
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 usando array_map
para agregar una sola cita a cada uno de los elementos en las $galleries
:
$galleries = array(1,2,5);
$galleries_str = implode('', '',
array_map(function(&$item){
return "''" .mysql_real_escape_string($item) . "''";
}, $galleries));
$sql = "SELECT * FROM gallery WHERE id IN (" . $galleries_str . ");";
La variante $ sql generada será:
SELECT * FROM gallery WHERE id IN (''1'', ''2'', ''5'');
Nota: mysql_real_escape_string , como se describe en mysql_real_escape_string , se desaprobó en PHP 5.5.0 y se eliminó en PHP 7.0.0. En su lugar, se debe usar la extensión MySQLi o PDO_MySQL. Consulte también MySQL: elección de una guía de API y preguntas frecuentes relacionadas para obtener más información. Las alternativas a esta función incluyen:
mysqli_real_escape_string ()
DOP :: cita ()
Más seguro
$galleries = array(1,2,5);
array_walk($galleries , ''intval'');
$ids = implode('','', $galleries);
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
Más un ejemplo:
$galleryIds = [1, ''2'', ''Vitruvian Man''];
$ids = array_filter($galleryIds, function($n){return (is_numeric($n));});
$ids = implode('', '', $ids);
$sql = "SELECT * FROM galleries WHERE id IN ({$ids})";
// output: ''SELECT * FROM galleries WHERE id IN (1, 2)''
$statement = $pdo->prepare($sql);
$statement->execute();
Manera segura sin DOP:
$ids = array_filter(array_unique(array_map(''intval'', (array)$ids)));
if ($ids) {
$query = ''SELECT * FROM `galleries` WHERE `id` IN (''.implode('','', $ids).'');'';
}
-
(array)$ids
Cast$ids
variable a array -
array_map
Transforma todos los valores de matriz en enteros -
array_unique
Eliminar valores repetidos -
array_filter
Eliminar valores cero -
implode
Unir todos los valores a la selección IN
Para MySQLi con una función de escape:
$ids = array_map(function($a) use($mysqli) {
return is_string($a) ? "''".$mysqli->real_escape_string($a)."''" : $a;
}, $ids);
$ids = join('','', $ids);
$result = $mysqli->query("SELECT * FROM galleries WHERE id IN ($ids)");
Para DOP con declaración preparada:
$qmarks = implode('','', array_fill(0, count($ids), ''?''));
$sth = $dbh->prepare("SELECT * FROM galleries WHERE id IN ($qmarks)");
$sth->execute($ids);
Podemos usar esta cláusula "WHERE id IN" si filtramos la matriz de entrada correctamente. Algo como esto:
$galleries = array();
foreach ($_REQUEST[''gallery_id''] as $key => $val) {
$galleries[$key] = filter_var($val, FILTER_SANITIZE_NUMBER_INT);
}
Como el siguiente ejemplo:
$galleryIds = implode('','', $galleries);
Es decir, ahora debería usar $query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";
Puede tener texts
tabla (T_ID (int), T_TEXT (text))
y test
tabla (id (int), var (varchar(255)))
En la insert into test values (1, ''1,2,3'') ;
lo siguiente generará filas de los textos de la tabla donde T_ID IN (1,2,3)
:
SELECT * FROM `texts` WHERE (SELECT FIND_IN_SET( T_ID, ( SELECT var FROM test WHERE id =1 ) ) AS tm) >0
De esta manera, puede administrar una simple relación de base de datos n2m sin una tabla adicional y usando solo SQL sin la necesidad de usar PHP o algún otro lenguaje de programación.
Suponiendo que desinfecte correctamente sus entradas de antemano ...
$matches = implode('','', $galleries);
Luego simplemente ajusta tu consulta:
SELECT *
FROM galleries
WHERE id IN ( $matches )
Cita los valores de manera apropiada dependiendo de tu conjunto de datos.
Utilizar:
select id from galleries where id in (1, 2, 5);
Un simple for each
bucle funcionará.
La manera de Flavius / AvatarKava es mejor, pero asegúrese de que ninguno de los valores de la matriz contenga comas.
ints:
$query = "SELECT * FROM `$table` WHERE `$column` IN(".implode('','',$array).")";
instrumentos de cuerda:
$query = "SELECT * FROM `$table` WHERE `$column` IN(''".implode("'',''",$array)."'')";
Utilizando DOP: [1]
$in = join('','', array_fill(0, count($ids), ''?''));
$select = <<<SQL
SELECT *
FROM galleries
WHERE id IN ($in);
SQL;
$statement = $pdo->prepare($select);
$statement->execute($ids);
Usando MySQLi [2]
$in = join('','', array_fill(0, count($ids), ''?''));
$select = <<<SQL
SELECT *
FROM galleries
WHERE id IN ($in);
SQL;
$statement = $mysqli->prepare($select);
$statement->bind_param(str_repeat(''i'', count($ids)), ...$ids);
$statement->execute();
$result = $statement->get_result();
Explicación:
Use el operador SQL IN()
para verificar si existe un valor en una lista dada.
En general se parece a esto:
expr IN (value,...)
Podemos construir una expresión para colocar dentro del ()
desde 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í asumo que la matriz que contiene sus identificadores se llama $ids
:
$in = join('','', array_fill(0, count($ids), ''?''));
$select = <<<SQL
SELECT *
FROM galleries
WHERE id IN ($in);
SQL;
Dada una matriz de entrada de tres elementos, $select
se verá así:
SELECT *
FROM galleries
WHERE id IN (?, ?, ?)
De nuevo nota 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 operador IN()
con cuerdas
Es fácil cambiar entre cadenas y enteros debido a los parámetros enlazados. Para PDO no hay cambio requerido; para MySQLi cambie str_repeat(''i'',
a str_repeat(''s'',
si necesita verificar cadenas.
[1]: He omitido algunos errores al verificar la brevedad. Debe verificar los errores habituales para cada método de base de datos (o configurar su controlador de base de datos para que genere excepciones).
[2]: Requiere PHP 5.6 o superior. Nuevamente he omitido algún error al verificar la brevedad.