此代码有效,但由于将GET参数连接到查询中,因此似乎不安全。我正在连接,因为我需要WHERE子句中的动态数量的参数可以是不同类型(IN
,正常比较条件)。
如何从动态数量的不同类型的WHERE条件中准备安全语句?
class myclass
{
public function index($where_clause = 1)
{
// db connection (using pdo)
$stm = $this->dbh->query("SELECT COUNT(amount) paid_qs FROM qanda $where_clause");
$ret = $stm->fetch(PDO::FETCH_ASSOC);
// do stuff
}
public function gen_where_clause()
{
$where_clause = '';
if (isset($_GET['c']) || isset($_GET['t']))
{
$where_clause = 'WHERE ';
if (isset($_GET['c']))
{
$where_clause .= 'cat = ' . $_GET['c'];
}
if (isset($_GET['t']))
{
if (isset($_GET['c']))
{
$where_clause .= $where_clause . ' AND '
}
$where_clause .= 'tag IN(' . $_GET['t'] . ')';
}
}
return $this->index($where_clause);
}
}
答案 0 :(得分:1)
我将在三个方面解决这个问题:代码的实际正确性,解决方案和更好的实践。
此代码实际上不工作,因为mentioned存在非常基本的语法错误,甚至会阻止它实际运行。我假设这是一个简化错误,但即使连接也是错误的:每次都重复该语句(。=和字符串本身。这些都将起作用,两者都会破坏查询)
$where_clause .= $where_clause . ' AND '
具有动态数量的参数的问题很有意思,并且根据需要可能相当复杂,但是在这种情况下,相当简单的参数连接将允许您实现动态数量的参数,如{{3 }}
更准确地说,当一个条件被添加到语句中时,单独将sql添加到语句中,并将值添加到数组中:
$sql .= 'cat = :cat';
$values[':cat'] = $_GET['c'];
然后,您可以准备语句并使用正确的参数执行它。
$stmt = $pdo->prepare($sql);
$stmt->execute($values);
如前所述,这个问题中提供的代码可能根本不起作用,所以让我强调一些基本的OOP原则,这些原则可以大大增强这个代码片段。
db连接应该通过构造函数注入,而不是每次执行查询时都重新创建(如果你在index
方法中连接的话)。请注意,$pdo
是私有财产。它不应该是公开的,可由其他对象访问。如果这些对象需要数据库连接,那么也在它们的构造函数中注入相同的pdo实例。
class myclass
{
private $pdo;
public function __construct(PDO $pdo) { $this->pdo = $pdo; }
}
其中一个方法应该是私有的,由另一个(公共方法)调用,它们将在参数中接收运行函数所需的所有内容。在这种情况下,似乎没有涉及任何参数,一切都来自$_GET
。
我们可以调整索引,使其接受sql和查询的值,但这三行可以很容易地转移到另一个方法。
private function index($sql, $values)
{
$stmt = $this->pdo->prepare($sql);
$stmt->execute($values);
return $stmt->fetchAll();
}
然后公共gen_where_clause(我相信它被错误地命名......它确实生成值,而不是子句)可以安全使用,这将生成动态数量的参数,保护您免受sql注入。
public function gen_where_clause()
{
$sql = "SELECT COUNT(amount) AS paid_qs FROM qanda ";
$values = [];
if (isset($_GET['c']) || isset($_GET['t']))
{
$sql .= ' WHERE ';
if (isset($_GET['c']))
{
$sql .= ' cat = :cat ';
$values[':cat'] = $_GET['c'];
}
// etc.
}
return $this->index($sql, $values);
}
对于sql注入保护,即使用参数化查询时,不需要转义值。但是,对输入进行消毒始终是一个正确的想法。在函数之外清理它,然后将其作为参数传递给"搜索"函数,将函数与超全局$_GET
解耦。定义过滤的参数超出了本文的相当大的范围,请参考suggested by AbraCadaver 。
// global code
// create $pdo normally
$instance = new myclass($pdo);
$inputs = filter_input_array(INPUT_GET, $args);
$results = $instance->gen_search_clause($inputs);