如果我需要根据某些变量从数据库中查询某些数据,有没有比这更好的方法了?
<?php
if($_POST['condition'] == '1'){
$sign = '<';
$number = '3';
} else if($_POST['condition'] == '2'){
$sign = '>';
$number = '10';
}
SELECT value1, value2 FROM table WHERE id $sign $number
?>
如果我有一个类似这样的简单查询,则可以使用此方法,但是我也需要在ORDER BY
中添加某些条件,我还需要添加另一个具有其他条件的AND
,查询很快看起来更像是变量,而不是查询。
还有另一种使用变量来更改查询的方法吗,如果我在查询中有很多这样的变量,这不好吗?
所有实际使用的查询都经过正确格式化(希望如此)并使用准备好的语句,例如。
答案 0 :(得分:0)
在这个级别上,我想说的是,除了编写一组完全生成sql的代码外,没有更好的方法。从一个角度来看,您实际上已经开始这样做了,而从另一个角度来看,这是一种方法对于这样的“ if x then this sql else that sql end”方案,会造成过度杀伤。有人建议正确地对值进行参数设置,但是如果您完全控制sql并且不将用户数据连接到其中,并且可能使思考变得更加复杂
就保持事物的可读性和清晰性而言,过多地编写比查询更可变的sql可能不值得。如果选择/变量受到限制(您的示例仅包含2个选择),则可以再次以更改后的形式再次写出查询,这可能会有更多的用途。
答案 1 :(得分:0)
是的,有更好的方法。除了使用准备好的语句防止SQL注入外,您还可以使用相同的数据在前端生成选择并构建查询。例如看这个功能:
public function getFilterOptions(): array
{
return [
['name' => 'Age >30', 'comparator' => '>', 'comparable' => 30],
['name' => 'Age until 21', 'comparator' => '<=', 'comparable' => 21],
];
}
然后您可以使用此方法在前端中生成过滤器选择:
echo '<select name="query_filter">';
foreach (getFilterOptions() as $key => $option) {
echo '<option value="' . $key . '">' . $option['name'] . '</option>';
}
echo '</select>';
请接受我的代码,因为我不知道提问者使用的是什么模板系统,使用纯PHP作为示例很有意义。
在过滤器代码中,您可以直接使用给定索引访问过滤器选项:
$optionIndex = $_POST['query_filter'];
// TODO: you should check first if this index exists and handle errors appropriately
$option = getFilterOptions()[$optionIndex];
// building the query will be easy then...
// note: it is not possible to dynamically bind operators of a query
$stmt = $pdo->prepare("SELECT * FROM persons WHERE age $option['comparator'] :comparable");
$stmt->execute($option);
// or explicit: $stmt->execute(['comparable' => $option['comparable']]);
// using PDO is actually not really necessary here as the options are hard coded
// and not user-given, but it is best practice anyway...
以这种方式进行操作的优点是,您可以将所有过滤器选项放在一个中央位置,从而使更改既容易又安全。而且,与使用多个if
和else if
语句相比,基于用户输入选择过滤器的代码要少得多。
当然,这只是一个非常基本的示例,您可以对其进行很多改进,尤其是使用更复杂的过滤器时。例如,您也可以将数据库列作为过滤器选项的一部分。但是我只是想向您提示可能的情况。
答案 2 :(得分:0)
正如一些SO人士所说,每个Web应用程序中的最佳实践是使用参数化语句。这样可以防止SQL注入,并提高性能。
您的用例的特殊性是:
不能将比较运算符作为参数传递(我想不出任何允许这样做的RDBMS)
您没有将POSTed值直接传递给查询。而是使用它们来决定在查询中应使用哪些值。这意味着您不会将自己暴露于SQL注入
结论是,您的方法看起来不错(前提是您确实对«$ number»参数使用了参数,而不是直接将其传递给查询-您说的是这样做,但没有显示该部分代码)。
当查询变得更加复杂时,您希望遵守上述原则(尽可能使用参数)。
如果复杂性变得难以管理,那么您可以考虑使用对象关系映射器 ORM ,它在代码和原始SQL之间创建了另一层间接访问,从而使您可以管理更多复杂的需求,而不必过多担心实际的SQL。 PHP提供了许多解决方案,例如Doctrine,propel,...
答案 3 :(得分:0)
您的查询是安全的,因此请忽略有关注入攻击的所有玩笑。
如果您希望一系列条件继续增长,那么我建议您使用查找数组而不是if-elseif-else
或case-switch
,因为它们最终会使您的脚本变得script肿。考虑这样的事情...
$conditions = [
1 => "< 3",
2 => "> 10",
];
if (empty($_POST['condition']) || !isset($conditions[$_POST['condition']])) {
// write default behavior
} else {
// use $conditions[$_POST['condition']] in your query
}
这种数据结构和过程使清洁,简明和高效的条件电池扩展成为可能。