是否有更好的方法来安全地传递变量而不是准备好的语句?

时间:2016-06-03 19:11:39

标签: php mysql pdo

预准备语句是一种非常好的方法,用于以高安全性和高效率将变量传递给查询。一切都很好。只是有一件小事有时让我感到不舒服。

实际上有时我的查询是动态的。而且我不知道我应该传递多少次变量。假设这个查询:

UPDATE user
   SET reputation = reputation + (CASE id WHEN :op THEN 2 WHEN :user THEN 15 END)
WHERE id in (:user, :op);

我应该传递2个变量($user$op),我必须将它们绑定两次:

$sth->bindValue(":op", $op, PDO::PARAM_INT);
$sth->bindValue(":user", $user, PDO::PARAM_INT);
$sth->bindValue(":user", $user, PDO::PARAM_INT);
$sth->bindValue(":op", $op, PDO::PARAM_INT);

有时候,查询会是这样的:

UPDATE user
   SET reputation = reputation + (CASE id WHEN :op THEN 2 WHEN :user THEN 15 END)
WHERE id in (:user, :op),

       fee = fee + 
         (CASE id WHEN :op   THEN (SELECT SUM(op_val) FROM money WHERE id = :post_id)
                  WHEN :user THEN (SELECT SUM(user_val) FROM money WHERE id = :post_id)
          END)
WHERE id in (:user, :op);

对于上面的查询,我应该再传递1个变量($post_id)。换句话说,4更多绑定值:

$sth->bindValue(":op", $op, PDO::PARAM_INT);
$sth->bindValue(":user", $user, PDO::PARAM_INT);
$sth->bindValue(":op", $op, PDO::PARAM_INT);
$sth->bindValue(":post_id", $post_id, PDO::PARAM_INT);
$sth->bindValue(":user", $user, PDO::PARAM_INT);
$sth->bindValue(":post_id", $post_id, PDO::PARAM_INT);
$sth->bindValue(":user", $user, PDO::PARAM_INT);
$sth->bindValue(":op", $op, PDO::PARAM_INT);

请参阅?我很难将变量传递给动态查询。我的意思是我必须多次传递一个变量。那么有没有其他方法来验证变量而不是预处理语句?

2 个答案:

答案 0 :(得分:3)

一般来说,可以:

  1. 定义一些user variables,然后由同一会话中的后续查询使用:

    $set = $pdo->prepare('SET @op = :op, @user = :user, @post = :post');
    $set->bindValue('op'  , $op  , PDO::PARAM_INT);
    $set->bindValue('user', $user, PDO::PARAM_INT);
    $set->bindValue('post', $post, PDO::PARAM_INT);
    $set->execute();
    
    $sth = $pdo->query('
      UPDATE user
      SET    reputation = reputation + CASE id
                            WHEN @op   THEN 2
                            WHEN @user THEN 15
                          END,
             fee        = fee + CASE id
                            WHEN @op   THEN (SELECT SUM(op_val)   FROM money WHERE id = @post)
                            WHEN @user THEN (SELECT SUM(user_val) FROM money WHERE id = @post)
                          END
      WHERE  id in (@user, @op)
    ');
    
  2. 创建一个包含变量的实体化表格,并将其加入查询:

    $sth = $pdo->prepare('
      UPDATE user
        JOIN (SELECT :op AS op, :user AS user, :post AS post) AS variables
      SET    reputation = reputation + CASE id
                            WHEN variables.op   THEN 2
                            WHEN variables.user THEN 15
                          END,
             fee        = fee + CASE id
                            WHEN variables.op   THEN (SELECT SUM(op_val)   FROM money WHERE id = variables.post)
                            WHEN variables.user THEN (SELECT SUM(user_val) FROM money WHERE id = variables.post)
                          END
      WHERE  id in (variables.user, variables.op)
    ');
    $sth->bindValue('op'  , $op  , PDO::PARAM_INT);
    $sth->bindValue('user', $user, PDO::PARAM_INT);
    $sth->bindValue('post', $post, PDO::PARAM_INT);
    $sth->execute();
    
  3. 但是,在这种特定情况下,可以将UPDATE分成两部分:

    $sth1 = $pdo->prepare('
      UPDATE user
      SET    reputation = reputation + 2,
             fee        = fee + (SELECT SUM(op_val) FROM money WHERE id = :post)
      WHERE  id = :op
    ');
    $sth1->bindValue('op'  , $op  , PDO::PARAM_INT);
    $sth1->bindValue('post', $post, PDO::PARAM_INT);
    
    $sth2 = $pdo->query('
      UPDATE user
      SET    reputation = reputation + 15,
             fee        = fee + (SELECT SUM(user_val) FROM money WHERE id = :post)
      WHERE  id = :user
    ');
    $sth2->bindValue('user', $user, PDO::PARAM_INT);
    $sth2->bindValue('post', $post, PDO::PARAM_INT);
    
    $sth1->execute();
    $sth2->execute();
    

答案 1 :(得分:2)

您可以在Execute中绑定变量。你仍然会准备声明。您可以在execute语句中将变量作为数组插入而不是bindParam()。

$stmt->execute(array(':var1'=>$var1, ':var2'=>$var2));