【问题标题】:Building WHERE clauses from multiple $_GET's从多个 $_GET 构建 WHERE 子句
【发布时间】:2013-09-12 17:43:07
【问题描述】:

我目前正在尝试编写从 $_GET 变量生成的复杂 MySQL WHERE 子句(这些变量本身来自选择下拉菜单)。首先,一些代码让你知道我在说什么:

    if(!isset($_GET['order'])){
        $order= 'start asc';
    } elseif ($_GET['order'] == "dateasc") {
        $order= 'start asc';
    } elseif ($_GET['order'] == "titleasc") {
        $order= 'title asc';
    } elseif ($_GET['order'] == "titledesc") {
        $order= 'title desc';
    };


    if(!isset($_GET['cat'])){
        $cat= '0';
    } else  {
        $cat = $_GET['cat'];
    };


    if(!isset($_GET['loc'])){
        $loc= '0';
    } else  {
        $loc = $_GET['loc'];
    };


    if (isset($_GET['sd']) || isset($_GET['ed']) || isset($_GET['cat']) || isset($_GET['loc']) || isset($_GET['order']) ) {
        $where = 'WHERE ';

        if (isset($_GET['sd'])) {
            $where .= "start = " . $_GET['sd'];
        };

        if (isset($_GET['ed'])) {
            $where .= "AND end = " . $_GET['ed'];
        };

        if (isset($_GET['cat'])) {
            $where .= "AND category = " . $_GET['cat'];
        };

        if (isset($_GET['loc'])) {
            $where .= "AND location = " . $_GET['loc'];
        };
    };


    $result = mysql_query("SELECT * FROM " . TABLE . $where . " ORDER BY " . $order);

显然这是行不通的,否则我不会在这里。 :) 基本上,我有 4 个变量有条件地用于在我的查询中进行排序:开始日期、结束日期、类别和位置。我的问题是所有这 4 个可能并不总是被使用.. 所以鉴于上面的例子,可能有人选择一个类别($cat)但不是开始日期($sd)......这意味着我的WHERE 子句将以“AND”开头,这显然是无效的。那么如何根据可能会或可能不会使用的变量构建查询呢?

我真的觉得我想多了,我害怕编写 9000 行 isset 测试来解释 $_GET 变量使用的每种组合。当然有一种简单的方法可以从多个 $_GET 构建 WHERE 子句,每次都可能使用也可能不使用......?我试过谷歌搜索,但只能找到建议使用框架来构建复杂查询的解决方案,而且对于这样一个简单的问题,这似乎过于......笨拙......

【问题讨论】:

  • 最简单的方法是在执行过程中将每个条件语句放入一个数组中,而不是直接构建 SQL。然后最后,您可以使用 AND 作为胶水来 implode() 您的数组。
  • 你不应该像这样将你的 GET 变量直接插入到你的 SQL 中。这不安全。看php.net/manual/en/book.mysqli.php
  • 建议:我认为对于复杂的条件语句,您应该使用 switch-statement.stackoverflow.com/questions/2158759/…
  • 请,在您编写任何更多的 SQL 接口代码之前,您必须阅读 proper SQL escaping 以避免严重的 SQL injection bugs。此外,mysql_query 不应在新应用程序中使用。这是一个已弃用的接口,已从 PHP 的未来版本中删除。像PDO is not hard to learn 这样的现代替代品,将使您的数据库代码更容易正确。
  • 感谢您的提示!我大部分时间都在做前端和 UI 方面的工作,所以我非常感谢所有的指点。

标签: php mysql sql where


【解决方案1】:

如果您只是担心 where 子句以 AND 开头,您可以添加 1=1 以说明没有过滤器。

WHERE 1=1

然后,如果您有任何过滤器,它将如下所示:

WHERE 1=1 AND col1=? AND col2=?

【讨论】:

    【解决方案2】:

    这可能不是最干净的解决方案,但应该相当容易理解和实施。

    if (isset($_GET['sd']) || isset($_GET['ed']) || isset($_GET['cat']) || isset($_GET['loc']) || isset($_GET['order']) ) {
        $where = 'WHERE ';
    
        if (isset($_GET['sd'])) {
            if(strlen($where) > 6) {
               $where .= " AND ";
            }
            $where .= "start = " . $_GET['sd'];
        }
    
        if (isset($_GET['ed'])) {
            if(strlen($where) > 6) {
               $where .= " AND ";
            }
            $where .= "end = " . $_GET['ed'];
        }
    
        if (isset($_GET['cat'])) {
            if(strlen($where) > 6) {
               $where .= " AND ";
            }
            $where .= "category = " . $_GET['cat'];
        }
    
        if (isset($_GET['loc'])) {
            if(strlen($where) > 6) {
               $where .= " AND ";
            }
            $where .= "location = " . $_GET['loc'];
        }
    }
    

    【讨论】:

    • 。这完全是疯了。您不能在查询中随意添加$_GET 内容。从任何干净的定义来看,这都不干净。
    • 我在 OPs 代码中添加了 if(strlen($where) > 6) { $where .= " AND "; }。 OP 没有要求我们帮助保护他的代码。他寻求帮助以减轻特定情况下的领先“AND”。保护您的代码免受 SQL 注入是否重要?是的。它总是很重要吗?不。有时我编写的应用程序只有我一个用户。
    • 它总是很重要,即使用户是你。有一天,您将搜索“O'Malley”类别,然后您将成为您草率编程的牺牲品。说真的,要求在那里拍一些mysql_real_escape_string 并永久解决问题是不是太过分了? SQL 注入漏洞可不是开玩笑的。不要把它们刷掉,因为没什么大不了的。 PHP 社区需要摆脱这种“不会发生在我身上”的态度。
    猜你喜欢
    • 2017-08-24
    • 1970-01-01
    • 2015-06-22
    • 2011-08-14
    • 1970-01-01
    • 2015-06-03
    • 1970-01-01
    • 1970-01-01
    • 2020-09-28
    相关资源
    最近更新 更多