¿Pueden las declaraciones PHP PDO aceptar el nombre de la tabla o columna como parámetro?
¿Por qué no puedo pasar el nombre de la tabla a una declaración PDO preparada?
$stmt = $dbh->prepare('SELECT * FROM :table WHERE 1');
if ($stmt->execute(array(':table' => 'users'))) {
var_dump($stmt->fetchAll());
}
¿Existe otra forma segura de insertar un nombre de tabla en una consulta SQL? Con seguro quiero decir que no quiero hacer
$sql = "SELECT * FROM $table WHERE 1"
Los nombres de tablas y columnas NO PUEDEN reemplazarse por parámetros en PDO.
En ese caso, simplemente querrás filtrar y desinfectar los datos manualmente. Una forma de hacer esto es pasar parámetros abreviados a la función que ejecutará la consulta dinámicamente y luego usar una switch()
declaración para crear una lista blanca de valores válidos que se usarán para el nombre de la tabla o el nombre de la columna. De esa manera, ninguna entrada del usuario va directamente a la consulta. Así por ejemplo:
function buildQuery( $get_var )
{
switch($get_var)
{
case 1:
$tbl = 'users';
break;
}
$sql = "SELECT * FROM $tbl";
}
Al no dejar ningún caso predeterminado o utilizar un caso predeterminado que devuelva un mensaje de error, se asegura de que solo se utilicen los valores que desea utilizar.
Para comprender por qué no funciona vincular el nombre de una tabla (o columna), debe comprender cómo funcionan los marcadores de posición en las declaraciones preparadas: no se sustituyen simplemente como cadenas (adecuadamente con escape) y se ejecuta el SQL resultante. En cambio, un DBMS al que se le pide "preparar" una declaración genera un plan de consulta completo sobre cómo ejecutaría esa consulta, incluidas las tablas e índices que usaría, que serán los mismos independientemente de cómo complete los marcadores de posición.
El plan SELECT name FROM my_table WHERE id = :value
será el mismo para cualquier cosa que sustituya :value
, pero lo que parece similar SELECT name FROM :table WHERE id = :value
no se puede planificar, porque el DBMS no tiene idea de qué tabla realmente va a seleccionar.
Esto tampoco es algo que una biblioteca de abstracción como PDO pueda o deba solucionar, ya que frustraría los 2 propósitos clave de las declaraciones preparadas: 1) permitir que la base de datos decida de antemano cómo se ejecutará una consulta y usar la misma planificar varias veces; y 2) evitar problemas de seguridad separando la lógica de la consulta de la entrada variable.