Question

J'aime la flexibilité de Dynamic SQL et la sécurité + les performances améliorées des instructions préparées. Donc, ce que je veux vraiment, ce sont les déclarations préparées dynamiques, ce qui est difficile à faire parce que bind_param et bind_result acceptent " fixed " nombre d'arguments. J'ai donc utilisé une instruction eval () pour contourner ce problème. Mais j'ai l'impression que c'est une mauvaise idée. Voici un exemple de code de ce que je veux dire

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

Cette dernière déclaration eval () est-elle une mauvaise idée? J'ai essayé d'éviter l'injection de code en encapsulant des valeurs derrière le nom de variable $ param.

Quelqu'un at-il une opinion ou une autre suggestion? Y a-t-il des problèmes dont je dois être au courant?

Était-ce utile?

La solution

Je pense qu'il est dangereux d'utiliser eval () ici.

Essayez ceci:

  • parcourez le tableau params pour construire la chaîne SQL avec des points d'interrogation "SELECT * FROM t1 WHERE p1 =? AND p2 =? & Quot;
  • appelez prepare () sur ce
  • utilisez call_user_func_array () pour appeler bind_param () , en transmettant le tableau de paramètres dynamiques.

Le code:

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

Autres conseils

J'ai créé une fonction de filtrage qui recueille un tableau en un tableau associatif tel que $ _GET:

Dans la classe de modèle, j'ai défini quelques propriétés, y compris le schéma:

private $table_name = "products";

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

Ensuite, une méthode de filtrage qui recive un tableau de conditions associatif:

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

Et fonctionne très bien pour filtrer les résultats

Vous n'avez pas vraiment besoin d'instructions préparées ni d'arguments liés, car vous pouvez toujours utiliser mysql_real_escape_string (). Et tu as raison SQL généré dynamiquement est beaucoup plus flexible et précieux.

Voici un exemple simple utilisant l'interface classique 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);

Bien sûr, c’est un exemple simpliste, et pour le rendre utile, vous devez le construire et le peaufiner beaucoup, mais cela montre les idées et c’est vraiment très très utile. Par exemple, voici une fonction complètement générique pour insérer une nouvelle ligne dans une table arbitraire, avec les colonnes remplies avec les valeurs d’un tableau associatif et totalement sécurisées pour l’injection 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));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top