0

PDOを使用するようにmysql関数を更新しています。私はそれのほとんどのコツを持っていますが、レコード内の複数のフィールドを更新するための更新機能に苦労しています。この関数はクラス内にあり、他のテーブルなどで再利用できるように柔軟性を維持しようとしています。

これまでの私の機能は次のとおりです。

 public function dbUpdateRecord($table, $values, $where)
{


    $this->conn();
    $fieldNames = array_keys($values);
    var_dump($fieldNames);
    $set="";
    foreach ($fieldNames as $field) {
        $set .= " $field = :$field,";
    }

    //strip last comma
    $set = substr($set, 0, strlen($set) - 1);


    $wherefields = array_keys($where);
    $whereCondition="";
    foreach ($wherefields as $field) {
        $whereCondition .= " $field = :$field AND";
    }
    //strip last AND
    $whereCondition = substr($whereCondition, 0, strlen($whereCondition) - 3);

    $sql = "UPDATE $table SET $set WHERE $whereCondition";
    var_dump($sql);

    $stmt = $this->db->prepare($sql);

    foreach ($values as $field => $value) {

        $stmt->bindParam(':$field', $value);
    }
    foreach ($where as $field => $value) {
        $stmt->bindParam(':$field', $value);
    }
    return $stmt->execute();
}

問題は、レコード内のすべてのフィールドが、$where変数に含まれているレコードのIDによって更新されていることです。

$ valuesには、(fieldname => value)の配列が含まれています。

問題はbindparamにあり、フィールド名/プレースホルダーを動的にしようとしていると思います

ベストプラクティスとしてbindparamを使用する必要があると思いました-これは正しいですか、それともexecute()に行くことができますか?

感謝します

4

3 に答える 3

2

このログを間違った端から持ち上げています。
あなたのアプローチは潜在的に安全ではありませんが、同時に柔軟性がありません。JOINベースのアップデートが必要な場合はどうなりますか?WHERE(またはIN)でORが必要な場合はどうなりますか?

本当に必要なのは、SETステートメント値のみを生成する必要がある従来のクエリです。したがって、データ配列からそのようなステートメントを生成し、正しくフォーマットされたSETステートメントとバインドされる変数を持つ配列の両方を返すヘルパー関数が必要です。

$fields = array("name","email");
$sql = "UPDATE users SET ".pdoSet($fields,$values,$data)." WHERE id = :id"
// now we have $values array to be passed into query
$stmt = $dbh->prepare();
$values["id"] = $_POST['id'];
$stmt->execute($values);

このコードを使用すると、任意のクエリを更新できます。そしてそれを安全にします。

さらなるステップとして、次のようなコード全体を作成するために、タイプヒント付きプレースホルダーの使用を開始する必要があります。

$db->query("UPDATE ?n SET ?u WHERE id IN(?a)",$table,$data,$ids);

問題に戻ると、ONeは正しいです-bindParamの代わりにbindValueを使用する必要があります(タグwikiで言及されているように)

于 2013-03-27T09:27:39.253 に答える
1

問題は、foreachを使用してパラメーターをクエリにバインドしていることだと思います。なぜこれが問題なのですか?変数をバインドするときは、その変数への参照をバインドするため、その変数が変更されると、クエリの値も変更されます。foreachループを使用しているため、すべてのパラメーターの値は、変数$valueが参照する最新の値になります。

このforeachの動作について詳しくは、こちらこちらをご覧ください。つまり、基本的に2つのオプションがあります。

  • $ valueへの参照を使用する代わりに、実際の値への参照を使用します(次の反復でその値を変更できます)
  • ループ中に変更されない別のメモリ位置を参照する補助変数を使用します
于 2013-03-27T09:08:22.630 に答える
0

私は同じ問題を抱えていたのでここに来ました、そしてYCSの解決策は私が必要としていたものでした。このような状況にある他の人のために、私が最終的に使用したヘルパー関数は次のとおりです。

function commit_table($ record_id、$ changed_values){$ db = open_database();

$query = 'UPDATE table SET ';
$query_arguments = array();

$is_first = TRUE;

foreach(array_keys($changed_values) as $key)
{
    if($is_first)
    {
        $is_first = FALSE;
    }
    else
    {
        $query .= ', ';
    }
    $value_var = ':' . $key;
    $query .= $key;
    $query .= ' = ';
    $query .= $value_var;
    $query_arguments[$value_var] = $changed_values[$key];
}

$query .= ' WHERE record_id = :record_id';
$query_arguments[':record_id'] = $record_id;

$stmt = $db->prepare($query);
$stmt->execute($query_arguments);

close_database($db);

}

于 2014-07-09T20:50:18.620 に答える