Dada uma matriz de IDs $galleries = array(1,2,5)
, quero ter uma consulta SQL que use os valores da matriz em sua cláusula WHERE, como:
SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */
Como posso gerar essa string de consulta para usar com o MySQL?
Respostas:
fonte
$galleries
deve ser validado antes desta declaração! As instruções preparadas não podem manipular matrizes AFAIK; portanto, se você estiver acostumado a vincular variáveis, poderá facilmente tornar possível a injeção de SQL aqui.$galleries
tinha o seguinte valor:array('1); SELECT password FROM users;/*')
. Se você não higienizar isso, a consulta será lidaSELECT * FROM galleries WHERE id IN (1); SELECT password FROM users;/*)
. Altere os nomes de tabela e coluna para algo que você tem no seu banco de dados e tente essa consulta, confira os resultados. Você encontrará uma lista de senhas como resultado, em vez de uma lista de galerias. Dependendo de como os dados são gerados, ou o que o script faz com uma matriz de dados inesperados, isso pode gerar resultados para a exibição pública ... ai.$galleries
fornecido na pergunta e você o explora usando a "vulnerabilidade de injeção de sql" acima mencionada. Se você não pode - você me paga USD200. Que tal isso?Usando DOP: [1]
Usando o MySQLi [2]
Explicação:
Use o
IN()
operador SQL para verificar se existe um valor em uma determinada lista.Em geral, é assim:
Podemos construir uma expressão para colocar dentro
()
do nosso array. Observe que deve haver pelo menos um valor entre parênteses ou o MySQL retornará um erro; isso equivale a garantir que nossa matriz de entrada tenha pelo menos um valor. Para ajudar a prevenir ataques de injeção SQL, primeiro gere um?
para cada item de entrada para criar uma consulta parametrizada. Aqui, eu assumo que a matriz que contém seus IDs é chamada$ids
:Dada uma matriz de entrada de três itens,
$select
será semelhante a:Observe novamente que existe um
?
para cada item na matriz de entrada. Em seguida, usaremos o DOP ou o MySQLi para preparar e executar a consulta conforme observado acima.Usando o
IN()
operador com stringsÉ fácil mudar entre seqüências de caracteres e números inteiros devido aos parâmetros associados. Para o DOP, não é necessária nenhuma alteração; para MySQLi, mude
str_repeat('i',
parastr_repeat('s',
se você precisar verificar as strings.[1]: omiti a verificação de erros por questões de concisão. Você precisa verificar os erros usuais para cada método de banco de dados (ou definir seu driver de DB para lançar exceções).
[2]: Requer PHP 5.6 ou superior. Mais uma vez, omiti a verificação de erros por questões de concisão.
fonte
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
, o...
item está expandindo os IDs de uma matriz para vários parâmetros. Se você está se referindoexpr IN (value,...)
, significa que pode haver mais valores, por exemploWHERE id IN (1, 3, 4)
. Só precisa haver pelo menos um....
: wiki.php.net/rfc/argument_unpackingints:
cordas:
fonte
Supondo que você desinfete corretamente suas entradas de antemão ...
Em seguida, basta ajustar sua consulta:
Cite os valores adequadamente, dependendo do seu conjunto de dados.
fonte
Usar:
Um
for each
loop simples funcionará.O caminho do Flavius / AvatarKava é melhor, mas verifique se nenhum dos valores da matriz contém vírgulas.
fonte
Como resposta de Flavius Stef , você pode usar
intval()
para garantir que todosid
sejam valores int:fonte
Para o MySQLi com uma função de escape:
Para DOP com declaração preparada:
fonte
Devemos cuidar das vulnerabilidades de injeção de SQL e de uma condição vazia . Eu vou lidar com ambos como abaixo.
Para uma matriz numérica pura, use a conversão de tipo apropriada viz
intval
oufloatval
oudoubleval
sobre cada elemento. Para tipos de stringmysqli_real_escape_string()
que também podem ser aplicados a valores numéricos, se desejar. O MySQL permite números, bem como variantes de data, como string .Para escapar adequadamente dos valores antes de passar para a consulta, crie uma função semelhante a:
Provavelmente, essa função já estará disponível para você no seu aplicativo ou talvez você já tenha criado um.
Desinfete a matriz de strings como:
Uma matriz numérica pode ser higienizado com
intval
oufloatval
oudoubleval
em vez como apropriado:Finalmente, crie a condição de consulta
ou
Como o array também pode estar vazio às vezes, como
$galleries = array();
devemos observar, issoIN ()
não permite uma lista vazia. Também se pode usarOR
, mas o problema permanece. Portanto, a verificação acimacount($values)
, é garantir o mesmo.E adicione-o à consulta final:
fonte
$query = 'SELECT * FROM galleries WHERE ' . (count($gallaries) ? "id IN ('" . implode("', '", array_map('escape', $gallaries)) . "')" : 0);
Mais seguro.
fonte
A biblioteca SafeMySQL da Col. Shrapnel para PHP fornece espaços reservados com sugestões de tipo em suas consultas parametrizadas e inclui alguns espaços reservados convenientes para trabalhar com matrizes. O
?a
espaço reservado expande uma matriz para uma lista separada por vírgula de seqüências de caracteres de escape *.Por exemplo:
* Observe que, como o MySQL executa coerção automática de tipo, não importa que o SafeMySQL converta os IDs acima em strings - você ainda obterá o resultado correto.
fonte
Podemos usar esta cláusula "WHERE id IN" se filtrarmos adequadamente a matriz de entrada. Algo assim:
Como no exemplo abaixo:
Ou seja, agora você deve usar com segurança
$query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";
fonte
Você pode ter mesa
texts
(T_ID (int), T_TEXT (text))
e mesatest
(id (int), var (varchar(255)))
A
insert into test values (1, '1,2,3') ;
seguir, serão exibidas linhas dos textos da tabela em queT_ID IN (1,2,3)
:Dessa forma, você pode gerenciar uma relação simples de banco de dados n2m sem uma tabela extra e usar apenas SQL sem a necessidade de usar PHP ou alguma outra linguagem de programação.
fonte
Mais um exemplo:
fonte
Além de usar a consulta IN, você tem duas opções para fazê-lo, pois em uma consulta IN existe o risco de uma vulnerabilidade de injeção SQL. Você pode usar o loop para obter os dados exatos que deseja ou pode usar a consulta com o caso OR
fonte
Maneira segura sem DOP:
(array)$ids
Converter$ids
variável em matrizarray_map
Transforme todos os valores da matriz em números inteirosarray_unique
Remova valores repetidosarray_filter
Remover valores zeroimplode
Associe todos os valores à seleção INfonte
Como a pergunta original está relacionada a uma matriz de números e eu estou usando uma matriz de seqüências de caracteres, não pude fazer os exemplos fornecidos funcionarem.
Eu descobri que cada string precisava ser encapsulada em aspas simples para trabalhar com a
IN()
função.Aqui está a minha solução
Como você pode ver, a primeira função envolve cada variável da matriz
single quotes (\')
e depois implode a matriz.NOTA:
$status
não possui aspas simples na instrução SQL.Provavelmente existe uma maneira melhor de adicionar aspas, mas isso funciona.
fonte
$filter = "'" . implode("','",$status) . "'";
'
dentro da string? Injeção de SQL vulnerável. Use PDO :: quote ou mysqli_real_escape_string.Abaixo está o método que usei, usando o PDO com espaços reservados nomeados para outros dados. Para superar a injeção de SQL, estou filtrando a matriz para aceitar apenas os valores inteiros e rejeitando todos os outros.
fonte
Os métodos básicos para impedir a injeção de SQL são:
Usando instruções preparadas e consultas com parâmetros, a consulta é considerada a melhor prática, mas se você escolher o método de caracteres de escape, poderá tentar meu exemplo abaixo.
Você pode gerar as consultas usando
array_map
para adicionar uma única citação a cada um dos elementos no$galleries
:O $ sql var gerado será:
fonte