【问题标题】:Building a dynamic PHP prepared statement from user entry从用户输入构建动态 PHP 准备语句
【发布时间】:2019-10-01 18:03:15
【问题描述】:

我有一个包含学生记录的数据库,大约有 50 列左右,所有这些都需要可搜索。我熟悉如何通过附加字段来构建动态搜索查询。我似乎找不到任何关于使用本质上是动态的准备好的语句来搜索 MySQL 数据库的示例。例如,在搜索时,您只会输入需要搜索的字段,那么,如何根据用户输入构建动态准备语句?

这是一个如何在没有准备好的语句的情况下执行此操作的示例,但是这很容易发生 SQL 注入。我需要用函数“清理”每个变量。但是,使用准备好的语句会更加安全。

function clean($con,$var){
    $var = trim($var);
    $var = strtolower($var);
    $var = mysqli_real_escape_string($con,$var);
    return $var;
}

if(isset($_REQUEST['sub'])){

    if(isset($_REQUEST['student_fname'])){
        $student_fname = null;
        if($_REQUEST['student_fname'] != ''){
            $student_fname = '&& `student_fname` = \''.clean($con,$_REQUEST['student_fname']).'\' ';
        }
    }
    if(isset($_REQUEST['student_lname'])){
        $student_lname = null;
        if($_REQUEST['student_lname'] != ''){
            $student_lname = '&& `student_lname` = \''.clean($con,$_REQUEST['student_lname']).'\' ';
        }
    }

    $sql = "SELECT * FROM `student_records` 
    WHERE 1=1 
    $student_fname
    $student_lname
    ORDER BY class ASC, student_lname ASC";
    echo $sql;
}

【问题讨论】:

  • 注意:最终会有更多的字段,这个例子只显示1
  • @mohit 该示例未显示如何动态构建准备好的语句..?
  • 如何在查询中使用表单字段值?作为 ANDed 值或 ORed 值?无论如何,您都需要检查每个可能输入的表单值,并在检查每个可能的输入时构建查询字符串。请edit您的问题,并附上一个示例,说明您的查询将如何包含至少 2 或 3 个值。
  • @Dave 它们将是 AND 值,我已经更新了示例

标签: php mysql mysqli prepared-statement


【解决方案1】:

与许多事情一样,使用 PDO 会容易得多。但是,就在我的脑海中,这就是我的处理方式。您需要在这里建造 3 个结构。 SQL,参数类型列表(“s”或“i”)和参数列表本身。这一切都很简单。

如果您以前没有这样做过,将其放入 bind_param() 函数可能会有点棘手,但是一旦您将所有参数放入数组中,as detailed elsewhere 和 argument unpacking operator 就可以很好地工作。

对于您的 POST 变量,请记住 empty() 检查数组元素是否存在,以及它是否为非空。这将为您节省额外的检查,唯一需要注意的是empty("0") === true。

<?php
if (isset($_REQUEST['sub'])) {
    $types = "";
    $where = [];
    $params = [];

    if (!empty($_REQUEST['student_fname'])) {
        $types .= 's';
        $where[] = 'student_fname = ?';
        $params[] = $_REQUEST['student_fname'];
    }
    if (!empty($_REQUEST['student_lname'])) {
        $types .= 's';
        $where[] = 'student_lname = ?';
        $params[] = $_REQUEST['student_lname'];
    }

    if (count($where)) {
        $where = "AND " . implode(" AND ", $where);
    } else {
        $where = "";
    }

    $sql = "SELECT * FROM student_records
    WHERE 1=1 
    $where
    ORDER BY class ASC, student_lname ASC";

    $stmt = $con->prepare($sql);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    while ($res = $stmt->get_result()) {
        // ....
    }
}

请注意,此代码允许某人列出整个数据库;如果这不是您的意图,请将所有内容都包含在 if (count($where)) 语句中。


在 PDO 中,事情要简单得多,不需要绑定,参数已经作为数组传递。

<?php
if(isset($_REQUEST['sub'])){
    $where = [];
    $params = [];

    if(!empty($_REQUEST['student_fname'])) {
        $where[] = 'student_fname = ?';
        $params[] = $_REQUEST['student_fname'];
    }
    if(!empty($_REQUEST['student_lname'])){
        $where[] = 'student_lname = ?';
        $params[] = $_REQUEST['student_lname'];
    }

    if (count($where)) {
        $where = "AND " . implode(" AND ", $where);
    } else {
        $where = "";
    }

    $sql = "SELECT * FROM student_records
    WHERE 1=1 
    $where
    ORDER BY class ASC, student_lname ASC";

    $stmt = $con->prepare($sql);
    $stmt->execute($params);
    $data = $stmt->fetchAll(\PDO::FETCH_ASSOC);
}

【讨论】:

  • 我相信你需要一个调用用户函数的引用数组。参数解包在这里更有用
  • 这确实触发了一些久违的记忆(我已经很长时间没有使用 mysqli 来解决除了回答 SO 问题之外的任何事情了。)
猜你喜欢
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
  • 2018-03-11
  • 2010-09-17
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
相关资源
最近更新 更多