2016-08-07 152 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

看起來乾淨,做我想要的東西一樣的東西!謝謝你的建議。 –