2

私のデータベースには、予約済みのキーワードである「status」のようなフィールドがあります。このコードは私にとってはうまく機能します(ステータスは``によってエスケープされます):

$sql = "UPDATE $table SET `status`='$status' WHERE `id`='123'";

しかし、今はプリペアドステートメントのみを使用したいです!My Database.class:

class Database extends \PDO {
    private $_sth; // statement
    private $_sql;

    public function update($tbl, $data, $where, $where_params = array()) {
        // prepare update string and query
        $update_str = $this->_prepare_update_string($data);
        $this->_sql = "UPDATE $tbl SET $update_str WHERE $where";
        $this->_sth = $this->prepare($this->_sql);

        // bind values to update
        foreach ($data as $k => $v) {
            $this->_sth->bindValue(":{$k}", $v);
        }

        // bind values for the where-clause
        foreach ($where_params as $k => $v) {
            $this->_sth->bindValue(":{$k}", $v);
        }

        return $this->_sth->execute();
    }

    private function _prepare_update_string($data) {
        $fields = "";
        foreach ($data as $k => $v) {
            $fields .= "`$k`=:{$k}, ";
        }
        return rtrim($fields, ", ");
    }
}

動作しない更新例:

$DB = new Database();
$DB->update("tablename",
        array("status" => "active"),
        "`username`=:username AND `status`=:status",
        array("username" => "foofoo", "status" => "waiting"));

それは、reservedキーワード「status」のせいだと思います。しかし、私はそれを逃れる方法がわかりません。_prepare_update_string($ data)のプレースホルダーを次のようにエスケープしようとしました:

bindValue("`:{$k}`", $v)

しかし、結果はありません。

私は解決策が非常に単純であり、それが私の脳の中で行き詰まったオーバーフローであることを願っています。;-)よろしくお願いします!

4

2 に答える 2

3

SQL文字列(prepare_update_stringだと思います)を作成するとき、およびデータをバインドする両方のforeachループで、増分カウントを実行してバインド値に追加します。したがって、「:status」は「:status1」になります。

何かのようなもの:

$i = 1;
foreach ($data as $k => $v) {
    $this->_sth->bindValue(":{$k.$i}", $v);
    $i++;
}

これにより、予約されたキーワードの問題が解決されます。

また、同じプレースホルダーに複数回バインドする必要がある問題(将来発生すると確信しています)も解決します。

たとえば、次の代わりに、:statusプレースホルダーの2つのバインドが原因でエラーがスローされます

SELECT * from table WHERE `status` = :status AND `otherfield` = :status

カウントを増やすと、これは次のようになります。

SELECT * from table WHERE `status` = :status1 AND `otherfield` = :status2

楽しみ。

于 2012-11-02T00:19:58.073 に答える
0

同様の問題があり、参照によってパラメーターを渡すことで解決しました

varchar(3)フィールドがあり、「aaa」値の代わりにポインターが渡されました

これは機能します(参照による$ val):

<?php
foreach ($params as $key => &$val) {
    $sth->bindParam($key, $val);
}
?>

これは失敗します(bindParamには&$ variableが必要なため、値で$ val):

<?php
foreach ($params as $key => $val) {
    $sth->bindParam($key, $val);
}
?>

参照:Viliのコメント

https://www.php.net/manual/pt_BR/pdostatement.bindparam.php

于 2021-05-24T19:15:44.257 に答える