1

所以说我有这样的查询:

$columnstr = "sum";
$valsstr = "sum + 5";

$query = "UPDATE mytable SET $columnstr = ?";
$updatenum = $db->prepare($query);
$updatenum->bindParam(1, $valsstr);
$updatenum->execute();

问题是我认为这行不通,并且由于各种原因我无法完全测试它。Sum 是一个整数列,但我将一个字符串绑定到它,希望它知道将 5 添加到“sum”。

它也需要像这样发送,因为它并不总是基于列的当前值。

在这种情况下我想发送的查询是:

"UPDATE mytable SET sum=sum+5"

任何输入将不胜感激,谢谢!

4

2 回答 2

1

它应该工作。据我所知,只有您直接指定值的列才能被参数化。

以下是有效的 SQL。

UPDATE mytable SET col1=col1+5, col2=?, col3=? WHERE mykey=?

我刚刚在 IBM DB2 9.7 中对其进行了测试,但多年来它一直是有效的语法。

于 2013-07-05T17:26:43.887 回答
1

您不能将查询参数用于表达式。参数仅代替单个标量值。所以不是 PDO 不能绑定字符串变量,而是你的字符串“sum+5”将被计算为一个整数,而不是一个 SQL 表达式。MySQL 对“sum+5”的整数值的想法是 0。

这不是 PDO 的限制,它是 SQL 的定义方式。无论客户端编程语言或 RDBMS 品牌如何,它都将以相同的方式工作。这是开发人员学习 SQL 的常见障碍。 参数不是字符串插值。 字符串插值发生在prepare(). 在解析 SQL 之后,在execute(). 参数值不能强制重新解析 SQL,因此不能在查询中引入额外的表达式语法。这就是它防止 SQL 注入的方式。

如果您的输入字符串有时可能是表达式,而有时可能是常量值,那么您的情况很复杂。您可以做的最好的事情是编写代码来测试您的输入字符串并进行字符串插值或参数化。

您可以将对象而不是字符串传递给数据库查询方法(PHP 是一种松散类型的语言,这很容易)。如果该值是一个对象,则将其插入到查询字符串中。如果方法参数是标量,则使用参数。

function my_update_method($args) {
  $params = array();
  $query = "UPDATE mytable SET ";
  foreach ($args as $column => $value) {
    if ($value instanceof SQLTerm)
    {
      $query .= "`" . $column . "` = " . $value; /* calls object's __toString() method */
    } else {
      $query .= "`" . $column . "` = ?";
      $params[] = $value;
    }
  }

  $updatenum = $db->prepare($query);
  $updatenum->execute($params);
}

SQLTerm 类只是一个字符串的包装器,它的唯一目的是成为一个对象而不是一个字符串,因此我们可以判断一个值何时是要参数化的字符串标量,还是不能参数化的表达式。

class SQLTerm
{
  protected $string;
  public function __construct($string) {
    $this->string = $string;
  }
  public function __toString() {
    return $this->string;
  }
}

这意味着调用者负责以一种避免 SQL 注入风险的方式创建 SQLTerm 对象。

于 2013-07-05T17:42:59.287 回答