Os nomes de tabela e coluna NÃO PODEM ser substituídos por parâmetros no PDO.
Nesse caso, você simplesmente deseja filtrar e limpar os dados manualmente. Uma maneira de fazer isso é passar parâmetros abreviados para a função que executará a consulta dinamicamente e, em seguida, usar uma switch()
instrução para criar uma lista branca de valores válidos a serem usados para o nome da tabela ou o nome da coluna. Dessa forma, nenhuma entrada do usuário entra diretamente na consulta. Então, por exemplo:
function buildQuery( $get_var )
{
switch($get_var)
{
case 1:
$tbl = 'users';
break;
}
$sql = "SELECT * FROM $tbl";
}
Ao deixar nenhum caso padrão ou usar um caso padrão que retorna uma mensagem de erro, você garante que apenas os valores que você deseja que sejam usados sejam usados.
array('u'=>'users', 't'=>'table', 'n'=>'nonsensitive_data')
etc)default
. Se estiver usando esse padrão, você deve rotular um de seuscase
s comodefault
ou adicionar um caso de erro explícito, comodefault: throw new InvalidArgumentException;
if ( in_array( $tbl, ['users','products',...] ) { $sql = "SELECT * FROM $tbl"; }
. Obrigado pela ideia.mysql_real_escape_string()
. Talvez aqui eu possa dizê-lo sem que alguém entre e diga "Mas você não precisa disso com a DOP"Para entender por que a ligação de um nome de tabela (ou coluna) não funciona, é necessário entender como funcionam os espaços reservados nas instruções preparadas: eles não são simplesmente substituídos em cadeias (como escapadas) e o SQL resultante é executado. Em vez disso, um DBMS solicitado a "preparar" uma instrução apresenta um plano de consulta completo sobre como executaria essa consulta, incluindo quais tabelas e índices ele usaria, quais serão os mesmos, independentemente de como você preenche os espaços reservados.
O plano para
SELECT name FROM my_table WHERE id = :value
será o mesmo, independentemente do que você substitua:value
, mas o aparentemente semelhanteSELECT name FROM :table WHERE id = :value
não pode ser planejado, porque o DBMS não tem idéia de qual tabela você realmente selecionará.Isso também não é algo que uma biblioteca de abstração como a DOP possa ou deva contornar, já que isso anularia os dois principais objetivos das instruções preparadas: 1) permitir que o banco de dados decida com antecedência como uma consulta será executada e use o mesmo planejar várias vezes; e 2) para evitar problemas de segurança, separando a lógica da consulta da entrada variável.
fonte
TOP
/LIMIT
/OFFSET
cláusulas, portanto isso seria um pouco fora do lugar como um recurso.Vejo que este é um post antigo, mas achei útil e pensei em compartilhar uma solução semelhante à sugerida pelo @kzqai:
Eu tenho uma função que recebe dois parâmetros como ...
No interior, verifico as matrizes que configurei para garantir que apenas tabelas e colunas com tabelas "abençoadas" sejam acessíveis:
Em seguida, a verificação do PHP antes de executar o DOP se parece com ...
fonte
$pdo->query($sql)
O uso do primeiro não é inerentemente mais seguro que o último, você precisa limpar a entrada, seja parte de uma matriz de parâmetros ou de uma variável simples. Portanto, não vejo nada de errado em usar o último formulário com
$table
, desde que você tenha certeza de que o conteúdo de$table
é seguro (alfanum mais sublinhados?) Antes de usá-lo.fonte
(Resposta tardia, consulte minha nota lateral).
A mesma regra se aplica ao tentar criar um "banco de dados".
Você não pode usar uma instrução preparada para vincular um banco de dados.
Ou seja:
não funciona. Use uma lista segura.
Nota lateral: eu adicionei esta resposta (como um wiki da comunidade) porque costumava fechar perguntas, onde algumas pessoas postavam perguntas semelhantes a essa na tentativa de vincular um banco de dados e não uma tabela e / ou coluna.
fonte
Parte de mim se pergunta se você poderia fornecer sua própria função de desinfecção personalizada tão simples quanto isto:
Eu realmente não pensei nisso, mas parece que remover qualquer coisa, exceto caracteres e sublinhados, pode funcionar.
fonte
MyLongTableName
é fácil ler corretamente, mas se você verificar o nome armazenado (provavelmente) provavelmenteMYLONGTABLENAME
não será muito legível,MY_LONG_TABLE_NAME
na verdade é mais legível.Select * From $table
. Uma lista de permissões ou correspondência estrita de padrões (por exemplo, "nomes que começam no relatório_ seguidos apenas de 1 a 3 dígitos") é realmente essencial aqui.Quanto à questão principal deste segmento, os outros posts deixaram claro por que não podemos vincular valores a nomes de colunas ao preparar instruções, então aqui está uma solução:
O exemplo acima é apenas um exemplo, então nem é preciso dizer que copiar-> colar não funcionará. Ajuste para suas necessidades. Agora, isso pode não fornecer 100% de segurança, mas permite algum controle sobre os nomes das colunas quando elas "entram" como seqüências dinâmicas e podem ser alteradas no final do usuário. Além disso, não há necessidade de criar alguma matriz com os nomes e tipos de colunas da tabela, pois eles são extraídos do information_schema.
fonte