2008-10-14 31 views
7

Me gusta la flexibilidad de Dynamic SQL y me gusta la seguridad + el rendimiento mejorado de las declaraciones preparadas. Entonces, lo que realmente quiero es declaraciones preparadas dinámicas, lo cual es problemático porque bind_param y bind_result aceptan una cantidad de argumentos "fija". Así que hice uso de una declaración eval() para evitar este problema. Pero tengo la sensación de que esta es una mala idea. Aquí está el código de ejemplo de lo que quiero decir¿Las declaraciones preparadas dinámicas son malas? (con php + mysqli)

// 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 esa última declaración de eval() una mala idea? Intenté evitar la inyección de código encapsulando valores detrás del nombre de la variable $ param.

¿Alguien tiene una opinión u otras sugerencias? ¿Hay algún problema que deba tener en cuenta?

+0

Es posible que desee formular su pregunta titular un poco, para que otros puedan encontrar su pregunta más fácilmente. – Tomalak

Respuesta

13

Creo que es peligroso usar eval() aquí.

Prueba esto:

  • iterar la matriz params para construir la cadena SQL con signos de interrogación "SELECT * FROM t1 WHERE p1 = ? AND p2 = ?"
  • llamada prepare() en ese
  • uso call_user_func_array() para realizar la llamada a bind_param(), pasando en los parametros dinámicos formación.

El código:

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

Ten cuidado con 'matriz ($ tipos) + $ param'. Si $ param es una matriz con un índice de 0, entonces ese valor en $ param se descartará a favor de $ types, y obtendrá un error por tener menos variables que las indicadas en la cadena. http://php.net/manual/en/language.operators.array.php – Tushar

-1

Usted realmente no necesita declaraciones preparadas y argumentos ligados, porque siempre se puede utilizar mysql_real_escape_string(). Y tienes razón; SQL generado dinámicamente es mucho más flexible y valioso.

Aquí está un ejemplo simple que utiliza regularmente interfaz mysql_ *:

// 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 que sea útil tiene que construir y refinar mucho, pero muestra la ideas y es realmente muy muy útil. Por ejemplo, aquí es una función completamente genérico para insertar una nueva fila en una tabla arbitraria, con las columnas rellenas con los valores de una matriz asociativa y completamente seguro de 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)); 
+2

Los parámetros enlazados añaden seguridad adicional más allá del escape. Es una buena práctica usarlos. – troelskn

+1

¿Podría mostrarme qué seguridad adicional ofrecen entonces? ¿De qué tipo de ataque estarías protegido con parámetros vinculados frente a mi solución? Porque si te refieres a la habilidad de un programador para cometer errores, prefiero tener las herramientas más poderosas que las que restringen las herramientas. – rix0rrr

+0

+1 Gracias hombre! ¡Esta es una buena solución! – RubyDubee

Cuestiones relacionadas