每次我想以安全的方式从数据库中获取数据时,是否有任何想法可以避免重复这个冗长的代码?
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'"));
任何建议对我都有帮助!!
答案 0 :(得分:1)
不要听起来很苛刻,但你的方法有很多问题。对你的问题最直接的问题是传递的$values
是乱码。
我希望example
中的bindValues()看起来像这样:
foreach ($values as $param => $value) {
$this->_query->bindValue($param, $value);
}
因此$values
example()
应该看起来像这样:
$values = array(':id' => 4, ':username' => 'alex')
供参考,请参阅PDOStatement::bindValue()
上的php-docs除此之外:
您只需将变量$table
传递给查询:
$sql = "SELECT * FROM {$table} WHERE {$x}";
这是不安全的!虽然您更关注传递给查询的值(这是可以理解的),但您仍然会遇到漏洞。
您的类database
将查询及其结果存储在类变量中。这是不必要的(数据库引擎有查询缓存,如果你想在php中缓存这些文件你应该导致缓存,例如通过将数据库包装在类cached_database
中)并且当你的查询/结果意外时可能会导致错误重复使用或混淆。
有很多方法可以通过提供错误的参数来搞乱你的查询,因为几乎所有这些都是数组,很难弄清楚要放在哪里的值。这使您的整个设置非常脆弱,例如它取决于传递给$params
的{{1}}和$extn
的正确数量,这几乎肯定会在将来出现问题。不仅因为很难弄清楚那里发生了什么,而且因为它(很可能)缺乏您将来可能想要使用的功能,例如example
或IN
的查询。它可以保护您免于编写几行代码,但在不使用它几周之后,您将花费时间来试图找出发生了什么以及如何使用它(可能更多)。相信我,我们都去过那里。 ;)
我认为你更安全地重复看起来有点重复的PDO东西,但很容易理解 - 尤其是当其他人接管或将来帮助你的时候 - 并且有很好的记录。
如果您觉得需要简化选择类似数据等常见任务,则应考虑使用Doctrine之类的ORM。即使只是Doctrine DBAL也可以帮助您,因为您获得了强大的SQL Query Builder。
如果您真的想保留代码并且不想使用其他库,请尝试使用婴儿步骤进行简化。每当一小部分以完全相同的方式重复 将其置于私有方法中。例如,您可以在第一个示例中使用这3行来执行此操作:
$这 - &GT; _query-&GT;执行(); $ this-&gt; _results = $ this-&gt; _query-&gt; fetchAll(PDO :: FETCH_OBJ); 返回$ this-&gt; _results;
获取您的第一个代码段:
BETWEEN
您可以通过将经常重复的位提取到较小的私有方法中来简化它:
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);
}
}
,您都不会意外地发送许多参数或给他们错误的名称或以其他方式搞乱SQL查询。您只需准确传递所需的值即可。如果它使你的代码更安全,更好理解,有时违反“不要重复自己”是可以的。