[Pregunta]: ¿Qué estoy haciendo mal con esta consulta PDO?

Iniciado por Leguim, 4 Mayo 2021, 00:21 AM

0 Miembros y 1 Visitante están viendo este tema.

Leguim

Estoy mejorando todas mis consultas, antes usaba este método:

Código anterior (siempre use esto y funciona correctamente), como "dato curioso" en esta consulta sino concateno '.($by).' no me devuelve datos, es decir que no puedo usar :by en la consulta. No entiendo por qué (si me pudieran ayudar con eso también)
Código (php) [Seleccionar]

$con = Connection(USERNAME, PASSWORD);
$query = $con->prepare('SELECT id_album FROM albums WHERE '.($by).' = :by_value');
$query->execute(array(':by_value' => $by_value));
$results = $query->fetchAll();


Pero viendo un poco parece ser que hacerlo de la siguiente manera es más eficiente y seguro:
Pero me dice "Uncaught Error: Call to a member function bindParam() on bool" busqué el error pero veo ninguna relación con lo que escribí, lo ví varias veces pero parece que todo está correcto.
Código (php) [Seleccionar]

$con = Connection(USERNAME, PASSWORD);
$query = $con->prepare('SELECT id_album FROM albums WHERE :by = :by_value');
$query = $con->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$query->bindParam(':by', $by);
$query->bindParam(':by_value', $by_value);
$query->execute();
$results = $query->fetchAll();

MinusFour

No creo que puedas parametrizar esa parte de la query. Hasta donde yo tengo entendido solo los valores, no los campos. Quizás se pueda hacer algo con la tabla de metadatos de MySQL pero no lo recomendaría.

El error sin embargo es porque PDO::setAtribute regresa true/false, así que ahí te cargas $query. Simplemente no guardes el resultado de esa función en $query... pero como te dije, no creo que puedas parametrizar esa parte de la query.

Y de la otra forma tienes que estar completamente seguro del contenido de $by porque ahí fácilmente tienes SQLi.

Leguim

Entonces tampoco se puede parametrizar los limites en una consulta, no?

Código (php) [Seleccionar]

"... ORDER BY id_x DESC LIMIT :start, :quantity"


donde start es 0, y quantity es 10.

MinusFour

Al parecer creo que eso es posible. Creo que me equivoque cuando dije que solo podemos parametrizar valores... sobre todo cuando emulas los prepared statements. Pero al parecer nombres de columnas (o al menos usar un placeholder para multiples columnas) no es posible.

Leguim

No creo que te hayas equivocado, esa consulta de los LIMIT :x, :y no funciona a no ser que concatene LIMIT '.($x).', '.($y)

No sé si se podría arreglar esta vulnerabilidad de inyecciones para estas variables que quedarán concatenadas, con alguna función para "limpiar". Para este caso puedo decir si es numerico x e y pero ya cuando la variable es una cadena se complica.

MinusFour

#5
Cita de: Leguim en  5 Mayo 2021, 01:36 AM
No creo que te hayas equivocado, esa consulta de los LIMIT :x, :y no funciona a no ser que concatene LIMIT '.($x).', '.($y)

No sé si se podría arreglar esta vulnerabilidad de inyecciones para estas variables que quedarán concatenadas, con alguna función para "limpiar". Para este caso puedo decir si es numerico x e y pero ya cuando la variable es una cadena se complica.

Hay ejemplos en SO donde si funciona, pero tienes que especificar PDO::PARAM_INT al parámetro con PDOStatement::bindValue. En la misma documentación de MySQL hace mención que esto es posible. No veo porque el driver no lo habría de tomar en cuenta.

WHK

Hola, cuando dices:

Citarno me devuelve datos

Es porque no tienes un error en la programación de tu código sino en el resultado de la consulta SQL.

Has probado realizar la consulta SQL manualmente a tu base de datos para comprobar que realmente te deba retornar valores?, por otro lado debes tener cuidado porque cuando parametrizas valores este aplica secuencias de escapes y encierra los valores en comillas simples, aplicar esto al nombre de una columna puede perjudicar la query final, no creo que sea una buena práctica hacer que el nombre de la columna sea dinámica, para eso te recomiendo mejor que tengas clases de php diferentes para cada caso, o sea, un modelo de datos por cada tabla y si necesitas repetir funciones como por ejemplo un crud (consultar, editar, eliminar) entonces debes hacer una clase base y extenderla.

Por otro lado, si $by fuera una constante de tipo string y la pasaras directamente sin parametrizar entonces no debería haber problemas, pero veo que lo estás haciendo de manera dinámica porque probablemente en tu proyecto web el usuario final el le pasa el nombre de la tabla por parámetro get o post y eso es una pésima práctica y extremadamente peligroso y la parametrización no te va a salvar de esa inyección porque los nombres de columnas no usan comillas simples sino apóstrofes "`" e incluso puntos para concatenar la raiz del origen, incluso guión bajo en caso de sql server, y la secuencia de escape de caracteres para "valores" no es la misma que para "nombres de tablas":

https://stackoverflow.com/questions/182287/can-php-pdo-statements-accept-the-table-or-column-name-as-parameter

CitarTable and Column names CANNOT be replaced by parameters in PDO.

Creo que en ves de buscar la manera de hacer funcionar tu query debes enfocarte en replantear el diseño de arquitectura de tu aplicación y reconstruir esa funcionalidad.

Saludos.