
devextreme等前端数据网格组件在进行远程数据过滤时,通常会发送一个结构化的json对象,其中包含一个filter字段。这个filter字段是一个数组,它以一种类似lisp或nosql的语法来表达过滤条件。例如:
{
"from": "get_data",
"skip": 0,
"take": 50,
"requireTotalCount": true,
"filter": [["SizeCd","=","UNIT"],"or",["SizeCd","=","JOGO"]]
} 其中filter数组的结构特点是:
- 单个条件表示为[字段名, 操作符, 值],例如["SizeCd","=","UNIT"]。
- 逻辑操作符(如"or"、"and")作为独立的字符串元素插入到条件之间。
我们的目标是将这样的数组转换为形如WHERESizeCd= 'UNIT' ORSizeCd= 'JOGO'的MySQL WHERE子句。
2. 使用PDO构建预处理语句使用PDO(PHP Data Objects)是PHP中推荐的数据库交互方式,因为它支持预处理语句,能够有效防止SQL注入。我们将创建两个辅助函数:一个用于生成带有占位符的SQL查询字符串,另一个用于提取参数值。
假设我们有以下过滤数组:
$filterArray = [
["SizeCd","=","UNIT"],
"or",
["SizeCd","=","JOGO"],
"or",
["SizeCd","=","PACOTE"]
]; 2.1 生成SQL查询字符串(带占位符)
arrayToQuery函数负责遍历过滤数组,根据数组元素的类型(条件数组或逻辑操作符)来构建SQL WHERE子句。对于条件数组,它将字段名用反引号包围,操作符直接使用,值则用?作为占位符。
<?php
/**
* 将过滤数组转换为带有占位符的SQL WHERE子句。
*
* @param string $tableName 目标表名。
* @param array $filterArray DevExtreme风格的过滤数组。
* @return string 包含WHERE子句的SQL SELECT语句。
*/
function arrayToQuery(string $tableName, array $filterArray) : string
{
// 确保表名被反引号包围,防止SQL注入(针对表名)。
$select = "SELECT * FROM `" . str_replace("`", "``", $tableName) . "` WHERE ";
$conditions = [];
foreach ($filterArray as $item) {
if (is_array($item)) {
// 处理单个条件:[字段名, 操作符, 值]
// 字段名用反引号包围,防止SQL注入(针对字段名)。
$fieldName = "`" . str_replace("`", "``", $item[0]) . "`";
$operator = $item[1];
// 值使用PDO占位符 '?'
$conditions[] = "{$fieldName} {$operator} ?";
} else {
// 处理逻辑操作符:"or", "and"
// 确保操作符是合法的SQL关键字
$lowerItem = strtolower($item);
if (in_array($lowerItem, ['and', 'or'])) {
$conditions[] = " {$lowerItem} ";
} else {
// 忽略或抛出异常,处理非法操作符
// 示例中简化处理,实际应用中应更严谨
}
}
}
// 将所有条件和逻辑操作符拼接起来
$select .= implode("", $conditions);
return $select;
}
?> 2.2 提取参数值
arrayToParams函数负责从过滤数组中提取所有条件的值,这些值将作为PDO预处理语句的绑定参数。
<?php
/**
* 从过滤数组中提取所有参数值。
*
* @param array $filterArray DevExtreme风格的过滤数组。
* @return array 包含所有参数值的数组。
*/
function arrayToParams(array $filterArray) : array
{
$return = [];
foreach ($filterArray as $item) {
if (is_array($item)) {
// 提取条件数组中的第三个元素(即值)
$return[] = $item[2];
}
}
return $return;
}
?> 2.3 PDO使用示例
将上述函数结合PDO进行实际查询:
Teleporthq
一体化AI网站生成器,能够快速设计和部署静态网站
182
查看详情
<?php
// 示例过滤数组
$filterArray = [
["SizeCd","=","UNIT"],
"or",
["SizeCd","=","JOGO"],
"or",
["SizeCd","=","PACOTE"]
];
// 数据库连接(请替换为您的实际连接信息)
try {
$dsn = "mysql:host=localhost;dbname=your_database_name;charset=utf8mb4";
$username = "your_username";
$password = "your_password";
$conn = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, // 禁用模拟预处理,使用真实预处理
]);
} catch (PDOException $e) {
die("数据库连接失败: " . $e->getMessage());
}
$tableName = "your_table_name"; // 您的表名
$sql = arrayToQuery($tableName, $filterArray);
$params = arrayToParams($filterArray);
echo "生成的SQL查询字符串: " . $sql . "\n";
echo "提取的参数: " . print_r($params, true) . "\n";
try {
$stmt = $conn->prepare($sql);
$stmt->execute($params);
$results = $stmt->fetchAll();
echo "查询结果:\n";
print_r($results);
} catch (PDOException $e) {
echo "查询执行失败: " . $e->getMessage() . "\n";
}
?> 输出示例:
生成的SQL查询字符串: SELECT * FROM `your_table_name` WHERE `SizeCd` = ? or `SizeCd` = ? or `SizeCd` = ?
提取的参数: Array
(
[0] => UNIT
[1] => JOGO
[2] => PACOTE
)
查询结果:
Array
(
// ... 您的查询结果 ...
) 3. 使用MySQLi构建查询语句(带转义)
如果您的项目仍在使用MySQLi扩展,并且无法切换到PDO,那么在构建动态SQL时,手动对值进行转义是至关重要的,以防止SQL注入。
3.1 生成SQL查询字符串(带转义)arrayToQueryMysqli函数与arrayToQuery类似,但它直接将值嵌入到SQL字符串中,并在嵌入前使用$mysqli-youjiankuohaophpcnreal_escape_string()进行转义。
<?php
/**
* 将过滤数组转换为完整的MySQLi查询字符串,并对值进行转义。
*
* @param mysqli $mysqli MySQLi连接对象。
* @param string $tableName 目标表名。
* @param array $filterArray DevExtreme风格的过滤数组。
* @return string 包含WHERE子句的完整SQL SELECT语句。
*/
function arrayToQueryMysqli($mysqli, string $tableName, array $filterArray) : string
{
// 确保表名被反引号包围,防止SQL注入(针对表名)。
$select = "SELECT * FROM `" . $mysqli->real_escape_string($tableName) . "` WHERE ";
$conditions = [];
foreach ($filterArray as $item) {
if (is_array($item)) {
// 处理单个条件:[字段名, 操作符, 值]
// 字段名用反引号包围,并进行转义以防万一。
$fieldName = "`" . $mysqli->real_escape_string($item[0]) . "`";
$operator = $item[1];
// 值使用 real_escape_string 进行转义,并用单引号包围。
$escapedValue = "'" . $mysqli->real_escape_string($item[2]) . "'";
$conditions[] = "{$fieldName} {$operator} {$escapedValue}";
} else {
// 处理逻辑操作符:"or", "and"
$lowerItem = strtolower($item);
if (in_array($lowerItem, ['and', 'or'])) {
$conditions[] = " {$lowerItem} ";
}
}
}
$select .= implode("", $conditions);
return $select;
}
?> 3.2 MySQLi使用示例<?php
// 示例过滤数组
$filterArray = [
["SizeCd","=","UNIT"],
"or",
["SizeCd","=","JOGO"],
"or",
["SizeCd","=","PACOTE"]
];
// 数据库连接(请替换为您的实际连接信息)
$mysqli = new mysqli("localhost", "your_username", "your_password", "your_database_name");
// 检查连接
if ($mysqli->connect_errno) {
die("数据库连接失败: " . $mysqli->connect_error);
}
$tableName = "your_table_name"; // 您的表名
$query = arrayToQueryMysqli($mysqli, $tableName, $filterArray);
echo "生成的SQL查询字符串: " . $query . "\n";
try {
$result = $mysqli->query($query);
if ($result) {
echo "查询结果:\n";
while ($row = $result->fetch_assoc()) {
print_r($row);
}
$result->free();
} else {
echo "查询执行失败: " . $mysqli->error . "\n";
}
} catch (Exception $e) {
echo "查询执行异常: " . $e->getMessage() . "\n";
} finally {
$mysqli->close();
}
?> 输出示例:
生成的SQL查询字符串: SELECT * FROM `your_table_name` WHERE `SizeCd` = 'UNIT' or `SizeCd` = 'JOGO' or `SizeCd` = 'PACOTE'
查询结果:
Array
(
// ... 您的查询结果 ...
) 4. 注意事项与最佳实践
-
SQL注入防护:
- PDO预处理语句是首选。 它们将SQL逻辑与数据分离,自动处理参数转义,是防止SQL注入最安全有效的方法。
- MySQLi的real_escape_string至关重要。 如果必须使用MySQLi且构建动态SQL,务必对所有用户输入的值进行real_escape_string处理,并且字段名和表名也应进行适当的验证或转义。
- 字段名和表名转义: 在MySQL中,字段名和表名通常用反引号(`)包围,以避免与SQL关键字冲突,并允许使用特殊字符或空格(尽管不推荐)。在代码中,我们对字段名和表名也进行了反引号处理,并对反引号本身进行了转义,以增加安全性。
- 操作符验证: 在实际应用中,应严格验证filterArray中的操作符(如=、>、<、LIKE等)和逻辑操作符(and、or),只允许使用白名单中的合法操作符,防止恶意注入或意外行为。
- 复杂条件处理: 本教程仅处理了扁平化的AND或OR连接的条件。DevExtreme的filter数组可以支持嵌套的AND/OR组(例如[["field1", "=", "value1"], "and", ["field2", ">", "value2"], "or", [["field3", "<", "value3"], "and", ["field4", "=", "value4"]]])。处理这类复杂结构需要更高级的递归解析逻辑。
- 错误处理: 在生产环境中,数据库操作应包含健壮的错误处理机制,例如使用try-catch块捕获PDOException或检查mysqli的错误属性。
- 性能考量: 对于非常复杂的过滤条件或大量数据,考虑在数据库层面建立合适的索引,以优化查询性能。
通过本教程,我们学习了如何将DevExtreme等前端框架生成的类NoSQL过滤数组转换为可执行的MySQL WHERE条件语句。我们分别探讨了使用PDO预处理语句和MySQLi配合real_escape_string的两种方法,并强调了SQL注入防护的重要性。选择适合您项目需求的方法,并始终将安全性放在首位,以构建健壮、可靠的数据查询功能。
以上就是将DevExtreme过滤数组转换为MySQL WHERE条件语句的详细内容,更多请关注知识资源分享宝库其它相关文章!
相关标签: mysql php word js 前端 json go sql注入 防止sql注入 php lisp sql mysql json 前端框架 try catch Filter mysqli pdo 字符串 递归 对象 nosql 数据库 大家都在看: MySQL哈希标签搜索的精确控制与安全实践 Laravel 教程:在 MySQL 数据库中有效存储和处理数组数据 Laravel 中处理和存储复杂数组数据到 MySQL 数据库的教程 在 Laravel 中处理数组数据并存储到 MySQL 数据库的策略 PHP动态网页数据库备份恢复_PHP动态网页MySQL数据库备份教程






发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。