代码之家  ›  专栏  ›  技术社区  ›  Bruno

在我的代码中阻止SQL注入时出错

  •  0
  • Bruno  · 技术社区  · 2 年前

    我有一张有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实现这一点??:/

    0 回复  |  直到 10 年前
        1
  •  1
  •   spencer7593    10 年前

    我会这样做:

    $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);
    

    你可能想把 prepare execute 。检查来自的返回 准备 在你打电话之前 处决 或者,配置PDO可以在发生错误时抛出异常,例如。

     $dbh->setAttribute(PDO::ERRMODE_EXCEPTION);
    
        2
  •  0
  •   jbafford    10 年前

    您将需要制作某种查询生成器。您还希望使用准备好的语句,而不是直接将用户提供的输入注入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 ,通过组合所有 标准 或者返回一个空字符串。然后将其直接添加到查询中,并使用构建的参数数组执行查询。然后,您可以像任何其他PDO查询一样对结果集进行迭代。

    除其他外,使用参数化SQL而不是直接注入变量的主要好处是可以保护您免受SQL注入攻击。

    请注意,有许多方法可以改进此代码。你可以很容易地把它放在函数中;增加复杂性以允许不同类型的比较(例如。 <> LIKE ); 甚至将其用作更复杂的查询生成器的基础,该查询生成器允许更复杂的逻辑,例如 ((age = :age AND room = :room1) OR (room = :room2)) ; 等等。你所做的取决于你的应用程序的需要。