2016-08-07 116 views
0

任何想法,以避免每当我想以安全的方式从数据库中获取数据重复这个冗长的乱码?php oop准备语句

public function test($param) { 
    $sql = "SELECT * FROM users WHERE id = :id AND item_id :item_id"; 
    $this->_query = $this->_db->pdo()->prepare($sql); 
    $this->_query->bindValue(':id', $param); 
    $this->_query->bindValue(':item_id', $parmas); 
    $this->_query->execute(); 
    $this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ); 
} 

我创造了良好的办法不乱绕了一个简单的像这样的

public function query($sql, $params = array()) { 
    $this->_error = false; 
    if($this->_query = $this->_pdo->prepare($sql)) { 
     if(count($params)) { 
      //outside of the loop 
      $x = 1; 
      foreach($params as $param) { 
       $this->_query->bindValue($x, $param); 
       $x++; 
      } 
     } 
     if($this->_query->execute()) { 
      $this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ); 
      $this->_count = $this->_query->rowCount(); 
     } else { 
      $this->_error = true; 
     } 
    } 
    return $this; 
} 

PDO已经在类的构造函数中定义。

//我在这里添加更多细节,这就是我试图做的。

public function example($table, $params = array(), $extn = array(), $values = array()) { 
    $x = ''; 
    $y = 0; 
    foreach($params as $param) { 
     $x .= $param; 
     if($y < count($params)) { 
      $x .= $extn[$y]; 
     } 
     $y++; 
    } 
    $sql = "SELECT * FROM {$table} WHERE {$x}"; 
    $this->_query = $this->_pdo->prepare($sql); 
    foreach($values as $value) { 
     $this->_query->bindValue($value); 
    } 
    $this->_query->execute(); 
    $this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ); 
} 

但即时得到这个错误警告:PDOStatement对象:: bindValue()预计,至少2个参数, 与此代码向下跌破

$test = new Example(); 
$test->example('users', array('id = :id', 'username = :username', 'id = :username', 'username = :id'), array(' AND ', ' OR ', ' AND '), array("':id', 4", "':username', 'alex'")); 

任何建议将有助于我!

+1

请说明您的具体问题或添加额外的细节,以确切地突出你所需要的。正如目前所写,很难确切地说出你在问什么。请参阅[如何提问](http://stackoverflow.com/help/how-to-ask)页面以获得澄清此问题的帮助。 –

+1

您可以将参数放在关联数组中,即$ params ='[id'=> $ id,'item_id'=> $ item_id]',并直接在execute语句中使用它。即''$ this - > _ query-> execute($ params);'然后按正常方式取回。 PDO将自动执行所有必需的绑定,因此您不需要。 –

回答

1

听起来不刺耳,但您的方法存在很多问题。最直接的问题是,通过$values是乱码。

我期望bindValues()在example看起来是这样的:

foreach ($values as $param => $value) { 
    $this->_query->bindValue($param, $value); 
} 

因此$valuesexample()应该是这个样子:

$values = array(':id' => 4, ':username' => 'alex') 

仅供参考看到PHP- docs on PDOStatement::bindValue()

除此之外:

你只是传递变量$table到查询:

$sql = "SELECT * FROM {$table} WHERE {$x}"; 

这是不安全的!虽然您更关心传递给查询的值(这是可以理解的),但您仍然会在此处遇到漏洞。

您的类database将查询及其结果存储在类变量中。这是不必要的(数据库引擎有查询缓存,如果你想要这些文件缓存在PHP中,你应该得到一个缓存,例如通过将数据库包装在类cached_database中),并且当你的查询/结果被意外重用或混淆时可能会导致错误。

有很多方法通过给出错误的参数来搞乱你的查询,并且因为几乎所有的数组都是数组,所以很难找出在那里放置什么值。这会使整个设置非常脆弱,例如这取决于正确的$params$extn传递给example这几乎肯定会在未来出现问题。不仅是因为很难弄清楚发生了什么,而且还因为它(很可能)缺少了您可能希望在未来使用的功能,例如INBETWEEN的查询。它可以让你避免编写几行代码,但是几个星期后你不会使用它,你会花时间试图弄清楚会发生什么以及如何使用它(可能还有更多)。相信我,我们都在那里。;)

我认为你更安全地重复PDO东西,它看起来有点重复,但很容易理解 - 特别是当其他人接管或将来会帮助你 - 并且有详细记录时。

如果您觉得需要简化选择类似数据等常见任务,您应该考虑使用类似于Doctrine的ORM。即使只是Doctrine DBAL可能会帮助你,因为你得到了强大的SQL Query Builder

如果你真的想保留你的代码并且不想使用其他库,可以使用婴儿步骤来简化它。每当小部分重复时,其方式与完全相同,将其置于私有方法中。例如,你可以在第一个例子中用这3行代码:

$ this - > _ query-> execute(); $ this - > _ results = $ this - > _ query-> fetchAll(PDO :: FETCH_OBJ); return $ this - > _ results;

你的第一个代码片段:

class database { 
    $_results = null; 
    /*** 
    @param array $param should be an array of two elements 
    ***/ 
    public function test($param = []) { 
     $sql = "SELECT * FROM users WHERE id = :id AND item_id :item_id"; 
     $this->_query = $this->_db->pdo()->prepare($sql); 
     $this->_query->bindValue(':id', $param); 
     $this->_query->bindValue(':item_id', $param); 
     $this->_query->execute(); 
     $this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ); 
     return $this->_results; 
    } 
} 

你可以通过你经常重复成更小的私有方法只是提取位简化它:

/* 
* Don't just call it "database", that's way to generic. 
* Try to give it an explicit name, for example UserRepository 
*/ 
class UserRepository 
{ 
    public function getUsersByIdAndItemId($id, $itemId) { 
     $sql = "SELECT * FROM users WHERE id = :id AND item_id :item_id"; 
     $query = $this->getPreparedQuery($sql); 
     // No need to simplify this: 
     $query->bindValue(':id', $id); 
     $query->bindValue('item_id', $itemId); 

     return $this->executeQuery($statement); 
    } 

    public function getAllUsers() 
    { 
     $sql = "SELECT * FROM users"; 
     $query = $this->getPreparedQuery($sql); 

     return $this->executeQuery($query); 
    } 

    private function getPreparedQuery($sqlQueryString) 
    { 
     /* 
     * No "$this->_query" 
     * You don't have to reuse it! Worst case scenario a diffeent 
     * method accidentally reuses the query and you get a PDOException. 
     */ 
     return $this->_db->pdo()->prepare($sqlQueryString); 
    } 

    private function executeQuery(\PDOStatement $query) 
    { 
     $statement->execute(); 

     /** 
     * Again no need to store this in a class variable. 
     * Worst case scenario you end up with a dirty state 
     * or mixed up data 
     */ 
     return $statement->fetchAll(PDO::FETCH_OBJ); 
    } 
} 

这比你的方法更安全,因为它是简单明了。您的输入始终是安全的,并且每当您使用UserRepsitory::findUsersByIdAndItemId()时,您都不会意外发送到许多参数,或给它们错误的名称或弄乱sql查询。你只需要传递你需要的值。有时违反“不要重复自己”是好的,如果它使你的代码更安全,更好理解。

+0

看起来干净,做我想要的东西一样的东西!谢谢你的建议。 –