Pregunta

Me gusta la flexibilidad de SQL dinámico y me gusta la seguridad + el rendimiento mejorado de los estados preparados. Entonces, lo que realmente quiero es un Dynamic Prepared Statements, que es problemático porque bind_param y bind_result aceptan " corregido " número de argumentos. Así que hice uso de una declaración eval () para solucionar este problema. Pero tengo la sensación de que esto es una mala idea. Aquí está el código de ejemplo de lo que quiero decir

// array of WHERE conditions
$param = array('customer_id'=>1, 'qty'=>'2');
$stmt = $mysqli->stmt_init();

$types = ''; $bindParam = array(); $where = ''; $count = 0;

// build the dynamic sql and param bind conditions
foreach($param as $key=>$val)
{
    $types .= 'i';
    $bindParam[] = '$p'.$count.'=$param["'.$key.'"]'; 
    $where .= "$key = ? AND ";
    $count++;
}

// prepare the query -- SELECT * FROM t1 WHERE customer_id = ? AND qty = ?
$sql = "SELECT * FROM t1 WHERE ".substr($where, 0, strlen($where)-4);
$stmt->prepare($sql);

// assemble the bind_param command
$command = '$stmt->bind_param($types, '.implode(', ', $bindParam).');';

// evaluate the command -- $stmt->bind_param($types,$p0=$param["customer_id"],$p1=$param["qty"]);
eval($command);

¿Es la última afirmación de eval () una mala idea? Intenté evitar la inyección de código encapsulando valores detrás del nombre de variable $ param.

¿Alguien tiene una opinión u otras sugerencias? ¿Hay problemas que debo tener en cuenta?

¿Fue útil?

Solución

Creo que es peligroso usar eval () aquí.

Prueba esto:

  • itere la matriz params para crear la cadena SQL con signos de interrogación " SELECT * FROM t1 WHERE p1 =? AND p2 =? & Quot;
  • llame a prepare () en eso
  • use call_user_func_array () para hacer la llamada a bind_param () , pasando la matriz de parámetros dinámicos.

El código:

call_user_func_array(array($stmt, 'bind_param'), array($types)+$param);

Otros consejos

Hice una función de filtro que recibe una matriz de una matriz asociativa como $ _GET:

En la clase modelo, he definido un par de propiedades, incluido el esquema:

private $table_name = "products";

protected $schema = [
    'id' => 'INT',
    'name' => 'STR',
    'description' => 'STR',
    'size' => 'STR',
    'cost' => 'INT',
    'active' => 'BOOL'
];

Luego, un método de filtro que recibe una serie de condiciones asociativas:

function filter($conditions)
{
    $vars   = array_keys($conditions);
    $values = array_values($conditions);

    $where = '';
    foreach($vars as $ix => $var){
        $where .= "$var = :$var AND ";
    }
    $where =trim(substr($where, 0, strrpos( $where, 'AND ')));

    $q  = "SELECT * FROM {$this->table_name} WHERE $where";
    $st = $this->conn->prepare($q);

    foreach($values as $ix => $val){
        $st->bindValue(":{$vars[$ix]}", $val, constant("PDO::PARAM_{$this->schema[$vars[$ix]]}"));
    }

    $st->execute();
    return $st->fetchAll(PDO::FETCH_ASSOC);
}

Y funciona muy bien para filtrar resultados

Realmente no necesitas declaraciones preparadas y argumentos enlazados, porque siempre puedes usar mysql_real_escape_string (). Y tienes razón; El SQL generado dinámicamente es mucho más flexible y valioso.

Aquí hay un ejemplo simple utilizando la interfaz mysql_ * regular:

// Array of WHERE conditions
$conds = array("customer_id" => 1, "qty" => 2);

$wherec = array("1");
foreach ($conds as $col=>$val) $wherec[] = sprintf("`%s` = '%s'", $col, mysql_real_escape_string($val));

$result_set = mysql_query("SELECT * FROM t1 WHERE " . implode(" AND ", $wherec);

Por supuesto, este es un ejemplo simplista, y para hacerlo útil tienes que construirlo y refinarlo mucho, pero muestra las ideas y es realmente muy, muy útil. Por ejemplo, aquí hay una función completamente genérica para insertar una nueva fila en una tabla arbitraria, con las columnas rellenas con los valores de una matriz asociativa y completamente segura para inyección SQL:

function insert($table, $record) {
    $cols = array();
    $vals = array();
    foreach (array_keys($record) as $col) $cols[] = sprintf("`%s`", $col);
    foreach (array_values($record) as $val) $vals[] = sprintf("'%s'", mysql_real_escape_string($val));

    mysql_query(sprintf("INSERT INTO `%s`(%s) VALUES(%s)", $table, implode(", ", $cols), implode(", ", $vals)));
}

// Use as follows:
insert("customer", array("customer_id" => 15, "qty" => 86));
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top