PHP MySQLi预准备语句使MySQLi查询连接不同的子句

问题描述 投票:1回答:1

我需要使用准备好的语句来更改此查询,有可能吗?

查询:

$sql = "SELECT id, title, content, priority, date, delivery FROM tasks " . $op . " " . $title . " " . $content . " " . $priority . " " . $date . " " . $delivery . " ORDER BY " . $orderField . " " . $order . " " . $pagination . "";

查询之前,有代码检查POST变量并更改查询中变量的内容。

//For $op makes an INNER JOIN with or without IN clause depending on the content of a $_POST variable
$op = "INNER JOIN ... WHERE opID  IN ('"$.opID."')";
//Or
$op = "INNER JOIN ... ";

//For $title (depends of $op):
$title = "WHERE title LIKE'%".$_POST["title"]."%'";
//Or
$title = "AND title LIKE'%".$_POST["title"]."%'";

//For $content:
$content = "AND content LIKE '%".$_POST["content"]."%'";

//For $priority just a switch:
$priority = "AND priority = DEPENDING_CASE";

//For $date and $delivery another switch 
$d = date("Y-m-d", strtotime($_POST["date"]));
$date = "AND date >= '$d' 00:00:00 AND date <= '$d' 23:59:59";
//Or $date = "AND date >= '$d' 00:00:00";
//Or $date = "AND date <= '$d' 23:59:59";

//For $orderField
$orderField = $_POST["column"];

//For $order
$order= $_POST["order"];

//For $pagination 
$pagination = "LIMIT ".$offset.",". $recordsPerPage;

我一直在Google上搜索它,但对我来说还不太清楚...

如何使用准备好的语句进行此查询?

编辑:

  • 查询可能更静态,但这意味着要制作不同的准备好的语句并根据$ _POST检查执行它。
  • 它取决于许多变量,因为此查询在包含搜索字段和按顺序排列的列的表中显示结果。

完整的查询示例如下(取决于$ _POST检查):

SELECT id, title, content, priority, date, delivery FROM tasks INNER JOIN op ON task.op = op.opId WHERE op IN (4851,8965,78562) AND title LIKE '%PHT%' AND content LIKE '%%' AND priority = '2' ORDER BY date DESC LIMIT 0, 10 
php mysqli prepared-statement
1个回答
2
投票

一个好问题。并感谢您转向准备好的陈述。经过多年的努力,似乎终于开始接受这个想法。

免责声明:将有指向我自己网站的链接,因为我在PHP方面已经为人们服务了20多年,并且对撰写有关最常见问题的文章很着迷。

是的,这完全有可能。查看我的文章How to create a search filter for mysqli,以获取功能齐全的示例。

对于WHERE部分,您需要创建两个单独的数组-一个包含带占位符的查询条件,另一个包含这些占位符的实际值,即:

WHERE子句

$conditions = [];
$parameters = [];

if (!empty($_POST["content"])) {
    $conditions[] = 'content LIKE ?';
    $parameters[] = '%'.$_POST['content ']."%";
}

依此类推,适用于所有搜索条件。

然后您可以使用implode字符串作为胶水来AND所有条件,并获得一流的WHERE子句:

if ($conditions)
{
    $where .= " WHERE ".implode(" AND ", $conditions);
}

该例程对于所有搜索条件都是相同的,但对于IN()子句将有所不同。

IN()子句

有点不同,因为您将需要更多的占位符和更多的值来添加:

if (!empty($_POST["opID"])) {
    $in  = str_repeat('?,', count($array) - 1) . '?';
    $conditions[] = "opID IN ($in)";
    $parameters = array_merge($parameters, $_POST["opID"]);
}

此代码将向?子句中添加与IN()中的元素一样多的$_POST["opID"]占位符,并将所有这些值添加到$parameters数组中。可以在我网站同一部分的相邻文章中找到该说明。

完成WHERE子句后,可以移至其余查询

ORDER BY子句

您不能参数化order by子句,因为字段名和SQL关键字不能用占位符表示。为了解决这个问题,请您使用我为此目的编写的whitelisting function。有了它,您可以使ORDER BY子句100%安全,但完全灵活。您所需要做的就是使用order by子句中允许的字段名称预定义数组:

$sortColumns = ["title","content","priority"]; // add your own

然后使用此便捷功能获取安全值:

$orderField = white_list($_POST["column"], $sortColumns, "Invalid column name");
$order = white_list($_POST["order"], ["ASC","DESC"], "Invalid ORDER BY direction");

这是一个智能功能,涵盖了三种不同的情况

  • [如果未提供任何值(即$ _POST [“ column”]为空),将使用白名单中的第一个值,因此它将用作默认值
  • 如果提供正确的值,它将在查询中使用
  • 如果提供的值不正确,则将引发错误。

LIMIT子句

LIMIT值被完美地参数化,因此您可以将它们添加到$parameters数组中:

$limit = "LIMIT ?, ?";
$parameters[] = $offset;
$parameters[] = $recordsPerPage;

最终集会

最后,您的查询将是这样的

$sql = "SELECT id, title, content, priority, date, delivery 
        FROM tasks INNER JOIN ... $where ORDER BY `$orderField` $order $limit"; 

并且可以使用以下代码执行

$stmt = $mysqli->prepare($sql);
$stmt->bind_param(str_repeat("s", count($parameters)), ...$parameters);
$stmt->execute();
$data = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);

其中$data是常规数组,包含查询返回的所有行。

© www.soinside.com 2019 - 2024. All rights reserved.