【问题标题】:Build dynamic WHERE clause in mySQL在 mySQL 中构建动态 WHERE 子句
【发布时间】:2013-12-02 15:39:05
【问题描述】:

我有这个代码,如果我只想按办公室名称搜索,它效果很好。但是,我需要能够通过“办公室和/或名字和/或姓氏”,三者的任意组合进行搜索。

$firstName      = $_POST["firstName"];
$lastName       = $_POST["lastName"];
$officeName     = $_POST ["officeName"];

$query = "SELECT 
e.*,
e.id emp_id,
o.*
";
$query .= "FROM 
employee_data e,
office o,
employee_office_pivot p
"; 
$query .= "WHERE 
1=1
AND e.id=p.employee_id
AND p.office_id=o.id
AND o.office_name= '".$officeName."'
";

如何构建 WHERE 子句,以便它接受三列中的任何一列,如果它们为空,则不接受。

谢谢, 理查德

【问题讨论】:

标签: php mysql where


【解决方案1】:

这样的?

$query .= "WHERE 
    1=1
    AND e.id=p.employee_id
    AND p.office_id=o.id
    AND (o.office_name= '".mysqli_real_escape_string($officeName)."'
        OR o.office_name= '".mysqli_real_escape_string($firstName)."'
        OR o.office_name= '".mysqli_real_escape_string($lastName)."')
    ";

我这里以mysqli_real_escape_string()为例,你应该使用正确和必要的预防措施来避免你的系统中的SQL注入。

【讨论】:

  • 这有效,但前提是我取出 mysqli_real_escape_string
  • 这可能是因为您没有使用mysqli 扩展名。你用哪一个来连接数据库?
  • 这是我的连接字符串。 $connection = mysqli_connect($dbhost, $dbuser, $dbpass, $dbname);
  • 能否在脚本开头添加这两行并重试? error_reporting(E_ALL); ini_set('display_errors', 1);
  • 它不知道使用哪个连接。您必须使用mysqli_real_escape_string($connection, $officeName)$connection->real_escape_string($officeName),后者可能更适合您明显的面向对象风格。来源:php.net/manual/de/mysqli.real-escape-string.php
【解决方案2】:

您可以使用数组来动态构造您的 SQL:

/**
 *  The items you expect to receive from $_POST. I prefer defining these ahead of time - when feasible - 
 *  so that you can reference them without worrying about throwing an error if they are not set.
 */
$options = array_fill_keys(array('firstName', 'lastName', 'officeName'), false);
$post = array_merge($options, $_POST);
/**
 *  Your base SQL query.
 */
$sql = 'SELECT ...columns... FROM ...tables... WHERE 1 = 1';
$where = array();
/**
 *  If $_POST items are present, sanitize and create SQL
 */
if ( $post['firstName'] ) {
    $where[] = "employee_first_name = '".mysqli_real_escape_string($post['firstName'])."'";
}
if ( $post['lastName'] ) {
    $where[] = "employee_last_name = '".mysqli_real_escape_string($post['lastName'])."'";
}
if ( $post['officeName'] ) {
    $where[] = "office_name = '".mysqli_real_escape_string($post['officeName'])."'";
}
/**
 *  One or more $_POST items were found, so add them to the query
 */
if ( sizeof($where) > 0 ) {
    $sql .= ' AND '.implode(' AND ', $where);   
}

您可以使用相同的技术将列、连接表等动态添加到 SQL 中。 (提示:使用数组构建整个 SQL 语句。)您也可以很容易地修改它以使用 AND 和 OR 的组合。

【讨论】:

    【解决方案3】:
    $values = array(
        'firstName'  => 'someFirstName',
        'lastName'   => 'someLastName',
        'officeName' => 'someOfficeName'
    );
    
    foreach( $values as $col => $val )
    {
        $where .= "$key = '$balue' ";
    }
    

    虽然这是 SQL 注入漏洞。

    【讨论】:

    • "虽然这是 SQL 注入漏洞。"如果您知道它非常不安全,为什么还要给出答案?
    • 因为数据清理取决于作者使用的是什么(即 PDO 或 mysql 或其他)。
    • 一目了然90%的进来的问题都有SQL注入漏洞。我敢打赌,你是这群人中的 1%,他们甚至知道什么是 SQL 注入以及为什么它是一个问题。传播一些知识并向人们展示如何保护自己,而不是躲在数据库驱动程序后面。
    • 正如您所说,“90% 的问题都有 SQL 注入漏洞”,这意味着必须在 90% 的问题答案中重写相同的清理代码,哇,你似乎是一个高效的程序员......我用粗体写了它,它很容易受到攻击。如果这个人真的在乎它,他会很容易地从成千上万个谈论它的问题中找到更多关于它的信息。如果不是我可能会编写清理代码,他不会注意它。
    • 为每个问题编写准备语句或添加 real_escape_string 真的没有那么难,这就是 SQL 注入需要进行的所有清理工作。 SQL 注入是一个非常危险的漏洞,非常常见且很容易缓解,只需在代码中添加几个字符即可。显然,应该进行更多的清理工作,但这更主观,修复 SQL 注入是简单而直接的。您在评论部分浪费的时间比不留下 SQL 注入漏洞要多得多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多