Domanda

Mi piace la flessibilità di Dynamic SQL e mi piace la sicurezza + prestazioni migliorate delle dichiarazioni preparate. Quindi quello che voglio davvero sono le dichiarazioni dinamiche preparate, il che è difficile da fare perché bind_param e bind_result accettano " fixed " numero di argomenti. Quindi ho fatto uso di un'istruzione eval () per aggirare questo problema. Ma ho la sensazione che sia una cattiva idea. Ecco un esempio di codice di ciò che intendo

// 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);

L'ultima affermazione eval () è una cattiva idea? Ho cercato di evitare l'iniezione di codice incapsulando i valori dietro il nome della variabile $ param.

Qualcuno ha un'opinione o altri suggerimenti? Ci sono problemi di cui devo essere consapevole?

È stato utile?

Soluzione

Penso che sia pericoloso usare eval () qui.

Prova questo:

  • itera l'array params per creare la stringa SQL con punti interrogativi " SELECT * FROM t1 DOVE p1 =? E p2 =? & Quot;
  • chiama prepar () su quello
  • usa call_user_func_array () per effettuare la chiamata a bind_param () , passando l'array params dinamico.

Il codice:

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

Altri suggerimenti

Ho creato una funzione filtro che riceve un array in un array asociativo come $ _GET:

Nella classe del modello ho definito un paio di proprietà incluso lo schema:

private $table_name = "products";

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

Quindi un metodo di filtro che riceve una matrice di condizioni asociative:

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);
}

E funziona benissimo per filtrare i risultati

Non hai davvero bisogno di istruzioni preparate e argomenti rilegati, perché puoi sempre usare mysql_real_escape_string (). E hai ragione; l'SQL generato dinamicamente è molto più flessibile e prezioso.

Ecco un semplice esempio usando la normale interfaccia 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);

Ovviamente, questo è un esempio semplicistico e per renderlo utile devi costruirlo e perfezionarlo molto, ma mostra le idee ed è davvero molto molto utile. Ad esempio, ecco una funzione completamente generica per inserire una nuova riga in una tabella arbitraria, con le colonne riempite con i valori di un array associativo e completamente sicure con SQL injection:

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));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top