php - 如何准备具有动态数量参数的语句?

标签 php mysql security pdo prepared-statement

此代码有效,但由于将 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);
    }
}

最佳答案

我将从三个方面解决这个问题:代码的实际正确性、解决方案和更好的做法。


代码

这段代码实际上有效,因为mentioned有非常基本的语法错误,甚至根本无法实际运行。我假设这是一个简化错误,但即使连接也是错误的:语句每次都是重复的(.= 和字符串本身。其中任何一个都可以工作,都将破坏查询)

$where_clause .= $where_clause . ' AND '

参数的动态数量

具有动态数量参数的问题很有趣,并且根据需要可能相当复杂,但是在这种情况下,相当简单的参数连接将允许您实现动态数量的参数,如suggested by AbraCadaver .

更确切地说,当一个条件被添加到语句中时,分别将sql添加到语句中,并将值添加到一个数组中:

$sql .= 'cat = :cat';
$values[':cat'] = $_GET['c'];

然后您可以准备语句并使用正确的参数执行它。

$stmt = $pdo->prepare($sql);
$stmt->execute($values);

更好的做法

如前所述,此问题中提供的代码可能根本不起作用,因此让我强调一些可以显着增强此代码段的基本 OOP 原则。

  • 依赖注入(inject)

数据库连接应该通过构造函数注入(inject),而不是每次执行查询时都重新创建(如果您在 index 方法中连接,它就会这样做)。请注意,$pdo 是一个私有(private)属性。它不应该是公共(public)的,不能被其他对象访问。如果这些对象需要数据库连接,也可以在它们的构造函数中注入(inject)相同的 pdo 实例。

class myclass
{
    private $pdo;
    public function __construct(PDO $pdo) { $this->pdo = $pdo; }
}
  • 流程

其中一个方法应该是私有(private)的,由另一个(公共(public)方法)调用,后者将在参数中接收运行函数所需的一切。在这种情况下,似乎没有涉及任何参数,一切都来自 $_GET

我们可以调整索引,使其接受 sql 和查询值,但这三行可以很容易地转移到其他方法。

private function index($sql, $values)
{
    $stmt = $this->pdo->prepare($sql);
    $stmt->execute($values);
    return $stmt->fetchAll();
}

然后是可以安全使用的公共(public) gen_where_clause(我相信它的命名是错误的......它实际上生成的是值,而不是子句),它将生成动态数量的参数,保护你免受 sql 注入(inject)。

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 注入(inject)保护,即使用参数化查询时,不需要转义值。但是,清理您的输入始终是一个正确的想法。在函数外部对其进行清理,然后将其作为参数传递给“搜索”函数,将函数与超全局 $_GET 解耦。定义过滤参数超出了本文的范围,请参阅 documentation .

// global code
// create $pdo normally
$instance = new myclass($pdo);
$inputs = filter_input_array(INPUT_GET, $args);
$results = $instance->gen_search_clause($inputs);

关于php - 如何准备具有动态数量参数的语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44527918/

相关文章:

php - 创建字段数组然后循环遍历 PHP 中的集合

php - 查询不返回结果,但手动执行时返回结果

scala - Play 2.3 cookie 在过期后仍然可用

android - 针对某人对 Android 应用程序进行逆向工程的 PubNub 安全性

mysql - 如何将多数据库同步到远程服务器中的一个中央数据库?

php - 在 PHP 中将 & 转换为 & for XML

PHP include 内部变量

php - if语句不回避insert查询

mysql - 数据库关系 - 多对多

mysql - 数据库架构可将多个标签附加到每篇博客文章