query php pdo

query - ¿Pueden las declaraciones PHP DOP aceptar el nombre de la tabla o columna como parámetro?



php pdo postgresql select (7)

El uso del primero no es intrínsecamente más seguro que el segundo, debe desinfectar la entrada, ya sea parte de una matriz de parámetros o una variable simple. Por lo tanto, no veo nada malo en usar el último formulario con $table , siempre que se asegure de que el contenido de $table sea ​​seguro (¿alfanum más guiones bajos?) Antes de usarlo.

¿Por qué no puedo pasar el nombre de la tabla a una declaración de DOP preparada?

$stmt = $dbh->prepare(''SELECT * FROM :table WHERE 1''); if ($stmt->execute(array('':table'' => ''users''))) { var_dump($stmt->fetchAll()); }

¿Hay otra forma segura de insertar un nombre de tabla en una consulta SQL? Con seguro me refiero a que no quiero hacer.

$sql = "SELECT * FROM $table WHERE 1"


En cuanto a la pregunta principal en este hilo, las otras publicaciones dejaron en claro por qué no podemos vincular los valores a los nombres de columna al preparar las declaraciones, así que aquí hay una solución:

class myPdo{ private $user = ''dbuser''; private $pass = ''dbpass''; private $host = ''dbhost''; private $db = ''dbname''; private $pdo; private $dbInfo; public function __construct($type){ $this->pdo = new PDO(''mysql:host=''.$this->host.'';dbname=''.$this->db.'';charset=utf8'',$this->user,$this->pass); if(isset($type)){ //when class is called upon, it stores column names and column types from the table of you choice in $this->dbInfo; $stmt = "select distinct column_name,column_type from information_schema.columns where table_name=''sometable'';"; $stmt = $this->pdo->prepare($stmt);//not really necessary since this stmt doesn''t contain any dynamic values; $stmt->execute(); $this->dbInfo = $stmt->fetchAll(PDO::FETCH_ASSOC); } } public function pdo_param($col){ $param_type = PDO::PARAM_STR; foreach($this->dbInfo as $k => $arr){ if($arr[''column_name''] == $col){ if(strstr($arr[''column_type''],''int'')){ $param_type = PDO::PARAM_INT; break; } } }//for testing purposes i only used INT and VARCHAR column types. Adjust to your needs... return $param_type; } public function columnIsAllowed($col){ $colisAllowed = false; foreach($this->dbInfo as $k => $arr){ if($arr[''column_name''] === $col){ $colisAllowed = true; break; } } return $colisAllowed; } public function q($data){ //$data is received by post as a JSON object and looks like this //{"data":{"column_a":"value","column_b":"value","column_c":"value"},"get":"column_x"} $data = json_decode($data,TRUE); $continue = true; foreach($data[''data''] as $column_name => $value){ if(!$this->columnIsAllowed($column_name)){ $continue = false; //means that someone possibly messed with the post and tried to get data from a column that does not exist in the current table, or the column name is a sql injection string and so on... break; } } //since $data[''get''] is also a column, check if its allowed as well if(isset($data[''get'']) && !$this->columnIsAllowed($data[''get''])){ $continue = false; } if(!$continue){ exit(''possible injection attempt''); } //continue with the rest of the func, as you normally would $stmt = "SELECT DISTINCT ".$data[''get'']." from sometable WHERE "; foreach($data[''data''] as $k => $v){ $stmt .= $k.'' LIKE :''.$k.''_val AND ''; } $stmt = substr($stmt,0,-5)." order by ".$data[''get'']; //$stmt should look like this //SELECT DISTINCT column_x from sometable WHERE column_a LIKE :column_a_val AND column_b LIKE :column_b_val AND column_c LIKE :column_c_val order by column_x $stmt = $this->pdo->prepare($stmt); //obviously now i have to bindValue() foreach($data[''data''] as $k => $v){ $stmt->bindValue('':''.$k.''_val'',''%''.$v.''%'',$this->pdo_param($k)); //setting PDO::PARAM... type based on column_type from $this->dbInfo } $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC);//or whatever } } $pdo = new myPdo(''anything'');//anything so that isset() evaluates to TRUE. var_dump($pdo->q($some_json_object_as_described_above));

Lo anterior es solo un ejemplo, por lo que no hace falta decir que copiar y pegar no funcionará. Ajuste para sus necesidades. Ahora, esto puede no proporcionar un 100% de seguridad, pero permite cierto control sobre los nombres de las columnas cuando "entran" como cadenas dinámicas y se pueden cambiar al final de los usuarios. Además, no es necesario crear una matriz con los nombres y tipos de columnas de su tabla, ya que se extraen del esquema de información.


Para comprender por qué el enlace de un nombre de tabla (o columna) no funciona, debe comprender cómo funcionan los marcadores de posición en las declaraciones preparadas: no se sustituyen simplemente como cadenas (escapadas adecuadamente) y se ejecuta el SQL resultante. En su lugar, un DBMS al que se le pidió que "prepare" una declaración presenta 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 para SELECT name FROM my_table WHERE id = :value será el mismo que sustituyas por :value , pero el SELECT name FROM :table WHERE id = :value similar a SELECT name FROM :table WHERE id = :value no se puede planificar, porque el DBMS no tiene idea de qué tabla En realidad vamos a seleccionar.

Esto no es algo que una biblioteca de abstracción como PDO pueda o deba solucionar, ya que anularía los dos propósitos clave de las declaraciones preparadas: 1) para permitir que la base de datos decida de antemano cómo se ejecutará una consulta, y use la misma planear varias veces; y 2) para evitar problemas de seguridad separando la lógica de la consulta de la entrada variable.


Una parte de mí se pregunta si podría proporcionar su propia función de desinfección personalizada tan simple como esto:

$value = preg_replace(''/[^a-zA-Z_]*/'', '''', $value);

Realmente no lo he pensado, pero parece que eliminar cualquier cosa, excepto los caracteres y los guiones bajos, podría funcionar.


Veo que este es un post antiguo, pero lo encontré útil y pensé que compartiría una solución similar a la que @kzqai sugirió:

Tengo una función que recibe dos parámetros como ...

function getTableInfo($inTableName, $inColumnName) { .... }

En el interior, comparo con las matrices que he configurado para garantizar que solo las tablas y columnas con tablas "benditas" sean accesibles:

$allowed_tables_array = array(''tblTheTable''); $allowed_columns_array[''tblTheTable''] = array(''the_col_to_check'');

Entonces la comprobación de PHP antes de ejecutar PDO parece ...

if(in_array($inTableName, $allowed_tables_array) && in_array($inColumnName,$allowed_columns_array[$inTableName])) { $sql = "SELECT $inColumnName AS columnInfo FROM $inTableName"; $stmt = $pdo->prepare($sql); $stmt->execute(); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); }


(Respuesta tardía, consultar mi nota al margen).

La misma regla se aplica cuando se intenta crear una "base de datos".

No puede utilizar una declaración preparada para enlazar una base de datos.

Es decir:

CREATE DATABASE IF NOT EXISTS :database

no trabajará. Utilice una lista segura en su lugar.

Nota al margen: Agregué esta respuesta (como un wiki de la comunidad) porque a menudo se usaba para cerrar preguntas, donde algunas personas publicaban preguntas similares a estas al intentar vincular una base de datos y no una tabla y / o columna.


Los nombres de tablas y columnas no se pueden reemplazar por parámetros en PDO.

En ese caso, simplemente querrá filtrar y sanear los datos manualmente. Una forma de hacerlo es pasar parámetros de taquigrafía a la función que ejecutará la consulta dinámicamente y luego usar una instrucción switch() 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 un caso predeterminado o utilizar un caso predeterminado que devuelve un mensaje de error, se asegura de que solo se utilicen los valores que desea utilizar.