Php 通过$\u POST构建动态SQL语句
因此,这更多的是关于如何获得最佳方法的意见 我有一种非常优雅的方法,可以用一个简单的WHERE子句构建一个简单的动态SQL语句。WHERE子句可以包括多个字段,但它受到限制,因为它不允许不同的运算符(比较运算符或逻辑运算符) 我可以用它构建以下内容:Php 通过$\u POST构建动态SQL语句,php,mysql,sql,Php,Mysql,Sql,因此,这更多的是关于如何获得最佳方法的意见 我有一种非常优雅的方法,可以用一个简单的WHERE子句构建一个简单的动态SQL语句。WHERE子句可以包括多个字段,但它受到限制,因为它不允许不同的运算符(比较运算符或逻辑运算符) 我可以用它构建以下内容: SELECT * from table_name WHERE field_1 = "value_1" AND field_2 = "value_2"; //or I can do SELECT * from table_name WHERE fie
SELECT * from table_name WHERE field_1 = "value_1" AND field_2 = "value_2";
//or I can do
SELECT * from table_name WHERE field_1 = "value_1" OR field_2 = "value_2";
//or I can do
SELECT * from table_name WHERE field_1 <> "value_1" AND field_2 <> "value_2";
并且不要忘记带有“IN”或类似语句的多个标准,这些语句也不会构建,即:
SELECT * from table_name WHERE field_1 IN("value_1","value_2, "value_3");
SELECT * from table_name WHERE field_1 LIKE "val%";
以下是我当前的代码:
// db contains my DB connection
$db = new DB();
$where = 'WHERE';
$criteria = array();
foreach ($_GET as $key => $value) {
$where = $where.' '.$key.'=? AND';
array_push($criteria,$value);
}
if(count($_GET) > 0){
// $sql will look like: SELECT * FROM table_name WHERE field_1 = ? AND field_2 = ?
// $criteria is an array of values to pair with the above prepared statement.
// Will look like: $criteria("value_1", "value_2")
$sql = 'SELECT * FROM mcl_data_gap '.$where;
$results = $db->query($sql,$criteria);
} else {
$sql = 'SELECT * FROM mcl_data_gap';
$results = $db->query($sql);
}
// .... continue on using above SQL statement
在上面的代码中,我使用了get,但我的假设是post也可以
我唯一想到的是插入更多的键值对,这些键值对包含编码格式中所需的运算符,这样我就可以查找这些运算符并基于它们构建语句,但我觉得有更好的方法,我希望您能提供帮助
我刚才想到的另一个选择是在将SQL传递给服务器并执行之前构建SQL
或者我可以发布包含WHERE语句整个段的对象吗?您正在使用动态值的查询参数(相等比较的右侧)。这很好 但不能对动态列名(比较的左侧)使用参数。这就是代码易受SQL注入攻击的原因。事先准备好的陈述无助于此 解决方案是确保来自$\u GET键的每个列名实际上都是表中的一列。换句话说,这称为输入的白名单
$mcl_data_gap_columns = ["field_1", "field_2", "field_3"];
您只希望处理与表中存在的列列表中的列相匹配的$\u GET参数。不在此列表中的任何内容都应忽略
对于具有多个值的谓词,您可以在PHP中通过在末尾使用“[]
”命名GET参数来访问它们
$terms = [];
$parameters = [];
// only look for $_GET keys that match one of the known columns.
// this automatically ignores all other $_GET keys.
foreach ($mc_data_gap_columns as $col) {
// get the single value, or the array of multiple values.
// convert to an array in either case.
if (isset($_GET[$col])) {
$values = (array) $_GET[$col];
$default_op = "=";
} elseif (isset($_GET[$col."[]"])) {
$values = $_GET[$col."[]"];
$default_op = "IN";
} else {
continue;
}
// if your comparison is anything other than equality,
// there should be another request parameter noting that.
if (isset($_GET[$col."_SQLOP"])) {
$op = $_GET[$col."_SQLOP"];
} else {
$op = $default_op;
}
只处理已知的操作。如果$op不是受支持的特定操作之一,请忽略它,否则将抛出错误
switch ($op) {
case "=":
case ">":
case "<":
case ">=":
case "<=":
case "<>":
// all these are simple comparisons of one column to one value
$terms[] = "$col $op ?";
$parameters[] = $values[0];
break;
case "BETWEEN":
// comparisons of one column between two values
if (count($values) != 2) {
error_log("$col BETWEEN: wrong number of arguments: " . count($values));
die("Sorry, there has been an error in your request.");
}
$terms[] = "$col BETWEEN ? AND ?";
$parameters[] = $values[0];
$parameters[] = $values[1];
break;
case "IN":
// comparisons of one column IN a list of any number of values
$placeholders = implode(",", array_fill(1, count($values), "?"));
$terms[] = "$col IN ($placeholders)";
$parameters = array_merge($parameters, $values);
break;
default:
error_log("Unknown operation for $col: $op");
die("Sorry, there has been an error in your request.");
}
}
我没有测试过上述代码,但它应该能说明这一点:
- 决不要在SQL查询中使用$\u GET input verbatim
- 始终根据固定的安全值列表筛选输入
- 或者使用
对一组固定的保险箱进行测试开关
如果您认为您的HTML页面是其他人向您的服务器提交请求的唯一方式,那么您就错了。任何人都可以创建他们想要的任何URL,并将其提交到您的站点,即使它包含您不期望的GET参数和值。您的代码易受SQL注入攻击。永远不要相信用户输入,即使是变量名。我不得不尝试一次,因为PHP会自动用下划线替换空格,但它不会替换制表符,而mysql接受制表符为空白。因此,有人不友好地试图查询
yourfile.php?%27;删除%09表格%09SomeImportantable;%09--=a
将成功地大幅精简数据库。SQL注入在这里是个问题。用户可以将$key
的值设置为任何值,这会给您带来很多问题。您仍然可以构建动态查询,但您应该键入所有SQL,并使用$\u GET
参数确定在最终查询中使用哪些SQL。SQL字符串和参数将传递给使用PDO准备语句查询my db的类。我的理解是PDO准备的语句用于防止SQL注入。Bill,你当然是对的,感谢你指出这一点,我自己应该认识到我过程中的弱点。我将花一点时间适当地接受你的建议和反馈。
$terms = [];
$parameters = [];
// only look for $_GET keys that match one of the known columns.
// this automatically ignores all other $_GET keys.
foreach ($mc_data_gap_columns as $col) {
// get the single value, or the array of multiple values.
// convert to an array in either case.
if (isset($_GET[$col])) {
$values = (array) $_GET[$col];
$default_op = "=";
} elseif (isset($_GET[$col."[]"])) {
$values = $_GET[$col."[]"];
$default_op = "IN";
} else {
continue;
}
// if your comparison is anything other than equality,
// there should be another request parameter noting that.
if (isset($_GET[$col."_SQLOP"])) {
$op = $_GET[$col."_SQLOP"];
} else {
$op = $default_op;
}
switch ($op) {
case "=":
case ">":
case "<":
case ">=":
case "<=":
case "<>":
// all these are simple comparisons of one column to one value
$terms[] = "$col $op ?";
$parameters[] = $values[0];
break;
case "BETWEEN":
// comparisons of one column between two values
if (count($values) != 2) {
error_log("$col BETWEEN: wrong number of arguments: " . count($values));
die("Sorry, there has been an error in your request.");
}
$terms[] = "$col BETWEEN ? AND ?";
$parameters[] = $values[0];
$parameters[] = $values[1];
break;
case "IN":
// comparisons of one column IN a list of any number of values
$placeholders = implode(",", array_fill(1, count($values), "?"));
$terms[] = "$col IN ($placeholders)";
$parameters = array_merge($parameters, $values);
break;
default:
error_log("Unknown operation for $col: $op");
die("Sorry, there has been an error in your request.");
}
}
if ($terms) {
$sql .= " WHERE " . join(" AND ", $terms);
}
$db->query($sql, $parameters);