【问题标题】:search dynamically PHP MYSQL PDO动态搜索 PHP MYSQL PDO
【发布时间】:2016-01-14 22:58:15
【问题描述】:

我有一个带有 3 个选择框的表单:年龄、房间、类型。

<form action="results.php" method="get">
<div class="form-group">
<select name="age">
     <option value>Any</option>
     <option value="1">15</option>
     <option value="2">25</option>
     <option value="3">30</option>
     <option value="4">40</option>
   </select>
</div>
<div class="form-group">
<select name="room">
     <option value>Any</option>
     <option value="1">1</option>
     <option value="2">2</option>
   </select>
</div>
<div class="form-group">
<select name="type">
     <option value>Any</option>
     <option value="1">Personal</option>
     <option value="2">Business</option>
   </select>
</div>
</form> 

我想用 PDO 做的是做一个小的搜索。 如果所有变量都为空,那么我的条件是:

$search = $db->query("SELECT * FROM table");

如果其中 1 个(例如年龄)不为空,那么我有:

 if(!empty($_GET['age'])){
$age = $_GET['age'];
$search = $db->query("SELECT * FROM table WHERE age = '$age'");
}

现在,如果其中 2 个是 npt 空的,我有:

if(!empty($_GET['age']) && !empty($GET['room'])){
    $age = $_GET['age'];
$room = $_GET['room'];
    $search = $db->query("SELECT * FROM table WHERE age = '$age' AND room = '$room'");
    }

为了避免所有可能的搜索组合,如果不为空,我如何使用该词进行搜索。我过去做过一个:

if(!empty($age)){
$where = "WHERE age = '$age'";
}

if(!empty($room)){
$where .= "and room = '$room'";
}

$query = "SELECT * FROM table $where";

如何使用 PDO 实现它? :/

【问题讨论】:

    标签: php mysql


    【解决方案1】:

    我会这样做:

    $param = array();
    $query = 'SELECT ... FROM t WHERE 1=1';
    
    if(!empty($_GET['age'])){
      $param['age'] = $_GET['age'];
      $query .= ' AND t.age = :age';
    }
    
    if(!empty($_GET['room'])){
      $param['room'] = $_GET['room'];
      $query .= ' AND t.room = :room';
    }
    
    if(!empty($_GET['type'])){
      $param['type'] = $_GET['type'];
      $query .= ' AND t.type = :type';
    }
    
    $dbh->prepare($query)->execute($param);
    

    您可能希望将prepareexecute 分开。在尝试调用execute 之前,请检查prepare 的返回值。或者,配置 PDO 可以在发生错误时抛出异常,例如

     $dbh->setAttribute(PDO::ERRMODE_EXCEPTION);
    

    【讨论】:

    • 它工作正常..它免受 SQL 注入攻击吗?
    • 是的。使用 prepared statementbind placeholders 是避免 SQL 注入漏洞的规范模式。您的代码仍然依赖于 PDO 函数使用的模式。 PDO 可以使用真实的服务器端预准备语句,但它也可以“模拟”预准备语句。在仿真模式下,PDO 负责正确转义 SQL 文本中包含的值。您的代码与 PDO 函数一样易受攻击。为了增加保护,您的代码可以对提供的值执行额外的“白名单”检查,拒绝无效值。
    【解决方案2】:

    您需要创建某种查询构建器。您还需要使用准备好的语句,而不是直接将用户提供的输入注入到 sql 查询中。这可能看起来像这样:

    <?php
    
    $search = [
        'age' => 42,
        'room' => 'Millyway',
    ];
    
    $criteria = [];
    $params = [];
    
    foreach($search as $field => $value) {
        $criteria[] = "$field = :$field";
        $params[$field] = $value;
    }
    
    $where = ($criteria ? ('WHERE ' . implode(' AND ', $criteria)) : '');
    
    $query = "SELECT * FROM tablename $where";
    $stmt = $db->prepare($query);
    $stmt->execute($params);
    
    while($obj = $stmt->fetchObject()) {
        // iterate over your result set
    }
    

    给定搜索词作为 $search 中的键值(可以是表中的任何列和值,并且需要从这些值的来源处填充),此代码将构建 $criteria,一个集合WHERE 子句片段(使用参数化的 sql 参数名称,而不是直接注入值)和 $params,要传递到(即将到来的)准备语句的参数列表。

    然后它在$where 中构建完整的WHERE 子句,方法是组合所有已构建的$criteria,或返回一个空字符串。然后将其直接添加到查询中,并使用构建的参数数组执行查询。然后,您可以像任何其他 PDO 查询一样迭代结果集。

    其中,与直接注入变量相比,使用参数化 SQL 的主要好处是它可以保护您免受 SQL 注入攻击。

    请注意,可以通过多种方式改进此代码。你可以很容易地把它放在一个函数中;增加复杂性以允许不同类型的比较(例如&lt;&gt;LIKE);甚至可以将其用作更复杂的查询构建器的基础,该构建器允许更复杂的逻辑,例如((age = :age AND room = :room1) OR (room = :room2));等等。你做什么取决于你的应用程序的需要。

    【讨论】:

    • 我使用了 $search = [ 'age' => $age, 'room' => $room];但它向我显示了我的数据库表的所有行..我做错了什么?我必须更改其他内容?
    • 我的错误,foreach 中的错字。应该是$search,而不是$criteria。答案已更新。
    • 可能是另一个错误?它现在向我显示空白页.. :/
    • foreach 中的变量名是我唯一更改的内容。如果它之前给你结果,而你现在得到一个错误(或什么都没有),那么其他地方可能有一个错误。
    猜你喜欢
    • 2016-10-16
    • 1970-01-01
    • 2011-03-21
    • 2017-10-25
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    • 1970-01-01
    • 2014-10-04
    相关资源
    最近更新 更多