Frage

Ich mag die Flexibilität der dynamischen SQL und Ich mag die Sicherheit + verbesserte Leistung von Prepared Statements. Also, was ich wirklich will Dynamische Prepared Statements, was mühsam ist zu machen, weil bind_param und bind_result „feste“ Anzahl der Argumente zu akzeptieren. Also machte ich die Verwendung eines eval () Anweisung, um dieses Problem zu bekommen. Aber ich habe das Gefühl, das eine schlechte Idee ist. Hier ist Beispielcode von dem, was ich meine

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

Ist das letzte eval () Anweisung eine schlechte Idee? Ich habe versucht, Code-Injektion zu vermeiden, indem Werte hinter dem Variablennamen $ param eingekapselt wird.

Hat jemand eine Meinung oder andere Vorschläge? Gibt es Fragen, die ich bewusst sein müssen?

War es hilfreich?

Lösung

Ich denke, es ist gefährlich eval() hier zu verwenden.

Versuchen Sie folgendes:

  • iterieren die params Array die SQL-Zeichenfolge mit Fragezeichen "SELECT * FROM t1 WHERE p1 = ? AND p2 = ?"
  • bauen
  • Aufruf prepare() auf, dass
  • verwenden call_user_func_array(), um den Anruf bind_param(), in den dynamischen params Array übergeben.

Der Code:

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

Andere Tipps

habe ich eine Filterfunktion, die eine Anordnung recives ein asociative Array wie $ _GET:

In Modellklasse habe ich definiert ein paar Eigenschaften, einschließlich dem Schema:

private $table_name = "products";

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

Dann wird ein Filterverfahren, das eine asociative Anordnungen von Bedingungen erhalten speichert:

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

Und funktioniert super Ergebnisse filtern

Sie nicht wirklich brauchen vorbereitete Anweisungen und Argumente gebunden, weil man immer mysql_real_escape_string () verwenden. Und du hast Recht; dynamisch generierte SQL ist weitaus flexibler und wertvoll.

Hier ist ein einfaches Beispiel der regelmäßige mysql_ * Schnittstelle:

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

Natürlich ist dies ein einfaches Beispiel, und macht es sinnvoll, müssen Sie ihm eine Menge bauen und zu verfeinern, aber es zeigt die Ideen und es ist wirklich sehr, sehr nützlich. Zum Beispiel ist hier eine völlig generische Funktion eine neue Zeile in eine beliebige Tabelle einzufügen, wobei die Spalten mit den Werten aus einem assoziativen Array gefüllt und vollständig SQL-Injektion sicher:

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));
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top