2012-07-17 15 views
8

Me enfrenta un pequeño problema. Estoy trabajando en una aplicación en este momento que requiere el uso de nombres dinámicos de tablas en MySQL.Escapar de forma segura los nombres de tablas dinámicas en MySQL usando Codeigniter

Básicamente, tengo un proceso de selección de álbumes de una base de datos basado en una serie de factores (género, duración de la reproducción, fecha de lanzamiento, etc.) - Hay una sección de este proceso que permite al usuario crear un montón de filtros personalizados ..

Los filtros personalizados devuelven un recuento al usuario de todos los álbumes dentro de ese criterio de selección. Las ID de esos álbumes se almacenan en una tabla con un número de serie/hash generado aleatoriamente (por ejemplo, albumSelección_20880f9c05d68a)

Lo hice de esta manera porque no quería almacenar una gran lista separada por comas en un campo (Realmente tonto) - Y no me apetecía enviar una matriz de valores a un campo oculto en mi HTML, ya que esto solo aumentaría el rendimiento de los datos (podrían ser miles de filas a la vez)

En CodeIgniter, estoy usando enlaces de consulta para generar mis consultas SQL, así:

select * from artists where artistName = ? AND albumTitle = ? 

la consulta se escapó entonces de forma automática cuando parametrizar la consulta

$query = $this->db->query($sql,array("Singer","Album")); 

Ahora viene la parte difícil

Si escribo mi consulta a ser algo como esto:

$sql = "select albumid from albums where albumid in (select albumid from albumSelect_?)"; 
$this->db->query($sql,array('20880f9c05d68a')); 

La consulta resultante se convierte en:

select `albumid` from `albums` where `albumid` in (select `albumid` from `albumSelect_'20880f9c05d68a'`) 

Y muy con razón, pero obviamente la consulta no es válida ...

Edición: Más información

La consulta podría ser parte de una consulta más grande, dependiendo de qué criterios el usuario selecciona. p.ej.

$sql = "select albumid from albums where albumid in(select albumid from tags where tag = ?) AND albumid in(select albumid from albumSelect_?)"; 

Me preguntaba si había una manera de conseguir este trabajo, o si alguien pudiera sugerir una alternativa mejor .. La concatenación del nombre de la tabla es, obviamente, no una opción.

¡Gracias de antemano!

de Dave

+0

Si hubiera normalizado sus datos, no tendría que hacer esto * o * almacenar una lista de álbumes separados por comas. Esto se llama una relación "tiene muchas cosas a través". – Xeoncross

Respuesta

1

Los mecanismos de escape son solo para cadenas de datos, no para nombres de esquema. En otras palabras, solo para el contenido de una tabla, no para su estructura . Por lo tanto, tendrá que pegar la cadena en la consulta usted mismo, o evitar el uso de tablas de esta manera. El ? de plantillas de consulta no lo ayudará allí.

Si pega la cadena en el nombre de la tabla, puede usar los mecanismos habituales de concatenación de cadenas PHP. Debe hacer para asegurarse de que compruebe la cadena contra una expresión regular estrictamente adecuada, para evitar la inyección de SQL. Asegúrese de que realmente solo pegue una sola cadena al azar del formato que genera, y nada más.

Como alternativa, puede tener una gran tabla, que contenga todas las selecciones, y usar una columna adicional para guardar su hash de identificación u otra clave adecuada para identificar una sola selección. De esta forma, no tendría que modificar el esquema de la base de datos durante las operaciones normales. Creo que la mayoría de los desarrolladores, incluido yo, preferirían evitar tales modificaciones por código de programa. Un buen diseño de la base de datos funciona con un esquema fijo.

+0

Hola MvG, he decidido crear una mesa alta como sugeriste. De todos modos, hacerlo de esta manera encaja mejor con el flujo de trabajo previsto, y para ser sincero, no sé por qué pensé en hacerlo de otra manera. ¡Gracias por tu ayuda! – Dave

0

Me suena como que desea utilizar SQL dinámico. Probablemente tengas que seguir por el camino prepared statements. Con ellos, puede llamar al PREPARE en la cadena y luego al EXECUTE. La concatenación normal funciona bien.

Eso debería permitirle construir su SQL como una cadena y ejecutarlo. Si utiliza la parametrización de CodeIgniter en combinación con los procedimientos almacenados de MySQL, puede llamar a una consulta como "CALL selectAlbums(?, ?)" (suponiendo que selectAlbums es el procedimiento almacenado que contiene el PREPARE para la consulta real), que devolverá el conjunto.

Si desea deshacerse de ' s en la salida, canalice los parámetros a través de CONCAT, lo que producirá una cadena normal.

+0

Las declaraciones preparadas no están pensadas para este tipo de cosas. Usan la sintaxis de declaración normal, por lo que no harán más fácil el uso de nombres de tablas dinámicas. Las declaraciones preparadas son solo una forma de aumentar el rendimiento almacenando en caché el plan de ejecución para una declaración determinada, de modo que el servidor ya sepa cómo calcular un resultado de un tipo determinado. – MvG

+1

No, eso es exactamente lo que puedes hacer con ellos. Incluso hay un ejemplo que usa una variable de cadena para el nombre de la tabla directamente en la documentación. Por favor leelo. Estás hablando de rutinas almacenadas. O, tal vez, las "declaraciones preparadas" de CodeIgniter, que son declaraciones preparadas de la API de MySQL, no el mecanismo SQL dinámico integrado en el motor. Hay una gran diferencia allí. – Naltharial

+0

OK, mi error. Tenía en mente la API C, y pensé que los elementos del lenguaje de las declaraciones preparadas del lado del servidor harían prácticamente lo mismo. Aparentemente lo hacen en muchos aspectos, pero el uso de cadenas y 'CONCAT' en el servidor abre nuevas formas. Perdón por el ruido aquí. Realmente debería haber leído los documentos para dos oraciones más que hice. – MvG

Cuestiones relacionadas