这个问题有点难以表达,但基本上我有一个形式。 这是一种帐户信息表单,人们可以在其中更改与其帐户关联的信息。 问题是整个表单都会提交,每个输入都是可选的(将输入留空,不进行更改)。例如,通过此表格,您可以更改您的城市、地址和电话。 但是,人们可以选择仅填写城市,然后按提交,然后该信息就会更新,所有其他信息保持不变。
这对于手头的代码可能更有意义,这是我用来完成此任务的 PHP;有 4 行注释包含代码,这些注释被保留下来,因为它们是试图回答我自己的问题;他们可能有助于解释我想要实现的目标:
// SQL HELPER
function prepared_Query($con, $sql, $params, $types = ""){
$types = $types ?: str_repeat("s", count($params));
$stmt = $con -> prepare($sql);
$stmt -> bind_param($types, ...$params);
$stmt -> execute();
return $stmt;
}
// TRIM ALL POST VARS
function trim_Val(&$val){
$val = trim($val);
}
array_filter($_POST, 'trim_Val');
// SANITIZE ALL INPUTS
$filter = ['filter' => FILTER_SANITIZE_STRING, 'flags' => FILTER_FLAG_ENCODE_HIGH | FILTER_FLAG_ENCODE_LOW];
$inputs = ['prov', 'city', 'addr', 'code', 'phone', 'phone_alt'];
$keys = array_fill_keys($inputs, $filter);
$values = filter_input_array(INPUT_POST, $keys);
unset($filter, $inputs, $keys); // cleanup
$sqlA = [];
foreach($values as $key=>$val){
if($val){
$$key = $val;
//$sqlA[] = "meta_".$key." = ?";
}
}
//$sqlA = implode(", ", $sqlA);
//$sql = "UPDATE _MAIN_meta SET ".$sqlA." WHERE meta_user = ?;";
//$stmt = prepared_Query($con, $sql, [$$key, $uid]);
if(!empty($prov)){
$sql = "UPDATE _MAIN_meta SET meta_prov = ? WHERE meta_user = ?;";
$stmt = prepared_Query($con, $sql, [$prov, $uid]);
$stmt -> close();
echo "Updated Province";
}
if(!empty($city)){
$sql = "UPDATE _MAIN_meta SET meta_city = ? WHERE meta_user = ?;";
$stmt = prepared_Query($con, $sql, [$city, $uid]);
$stmt -> close();
echo "Updated City";
}
if(!empty($addr)){
$sql = "UPDATE _MAIN_meta SET meta_addr = ? WHERE meta_user = ?;";
$stmt = prepared_Query($con, $sql, [$addr, $uid]);
$stmt -> close();
echo "Updated Address";
}
if(!empty($code)){
$sql = "UPDATE _MAIN_meta SET meta_code = ? WHERE meta_user = ?;";
$stmt = prepared_Query($con, $sql, [$code, $uid]);
$stmt -> close();
echo "Updated Postal Code";
}
if(!empty($phone)){
$sql = "UPDATE _MAIN_meta SET meta_phone = ? WHERE meta_user = ?;";
$stmt = prepared_Query($con, $sql, [$phone, $uid]);
$stmt -> close();
echo "Updated Phone";
}
if(!empty($phone_alt)){
$sql = "UPDATE _MAIN_meta SET meta_phone_alt = ? WHERE meta_user = ?;";
$stmt = prepared_Query($con, $sql, [$phone_alt, $uid]);
$stmt -> close();
echo "Updated Alt. Phone";
}
$con -> close();
正如你可能会告诉我的那样,我一遍又一遍地重复最后一个函数,当它可以通过一次执行完成时,重复运行
$stmt
似乎很愚蠢。根据我在 PHP 和编程基础知识方面所学到的知识,这是非常 WET 的代码,其中 T 不再是两倍,而是 6 倍太多。 为了解决这个问题,我创建了一个数组,然后设置了 foreach
输入;将列名添加到该数组中。 一旦完成 implode
使用逗号分隔符的数组。 最后使用该内爆数组创建 SQL 语句。
这将根据设置的任何输入输出动态构建的 SQL 语句。 因此,如果城市和地址包含数据,则语句将如下所示:
$sql = "UPDATE _MAIN_meta SET meta_city = ?, meta_addr = ? WHERE meta_user = ?;";
现在我已经完成了这一点,具体取决于我填写的输入,SQL 语句的最终输出正是我想要的。
...当涉及到将该语句绑定到变量变量时,我有的是。 当我不知道设置了哪些参数时,我不知道是否有可能将设置的 var-vars 的 ALL 放入此
prepared_Query()
函数的参数中。
可能我的逻辑有缺陷,但我非常接近让它发挥作用,我不得不问是否有一种方法可以实现这一点,或者这样做是否有意义。 这对我来说是有道理的,但我之前也曾使用 PHP 陷入过一些非常令人讨厌的黑洞。 我确信有人比我更有常识..在做这样的事情时。
所以我的问题是,当每个变量都是可选的时,如何将变量绑定到准备好的 SQL 语句。 有没有办法不必为每个输入编写单独的语句? 或者更短/更快的方法来做到这一点?
这些问题很相似,但没有回答我的问题:
似乎还有其他一些问题是这样表述的,但我找不到有人试图解决此类问题的明确例子。 这就是让我觉得我的逻辑有缺陷的原因。
有人能给我指出正确的方向吗?
注意:我想我已经粘贴了与问题相关的所有内容,如果有不清楚的地方请告诉我。
其他两个答案都几乎很好。
@sh4dowb 的答案非常适合构建 SELECT 查询,其中可能存在难以自动化的不同条件。但对于 UPDATE 查询,手动选择每个子句是没有用的,循环将是一个更干净的解决方案。
@ooa 演示的方法更好,但他们忘记创建实际的更新子句。而且,它正在使用这些卑鄙变量。
但正确的解决方案几乎就在眼前。我们将使用我的 PDO 示例来完成同样的事情,如何为 UPDATE 查询创建准备好的语句:
// the list of allowed field names
$allowed = ['prov', 'city', 'addr', 'code', 'phone', 'phone_alt'];
// initialize an array with values:
$params = [];
// initialize a string with `fieldname` = ? pairs
$setStr = "";
// loop over source data array
foreach ($allowed as $key)
{
if (!empty($_POST[$key]) && $key != "id")
{
$setStr .= "`$key` = ?,";
$params[] = $_POST[$key];
}
}
$setStr = rtrim($setStr, ",");
$params[] = $_POST['id'];
$mysqli->execute_query("UPDATE _MAIN_meta SET $setStr WHERE main_user = ?", [$params]);
看在上帝的份上,忘记变量吧。它们“绝对没有用例”,但它们却可以造成“相当大的伤害”。 $_POST
数组是数据的绝佳来源,不需要其他任何东西。
您可以扩展数组并添加参数名称和类型,如
PARAM_INT
。此外,如有必要,您应该仅检查并添加
WHERE
一次,例如当您在查询中默认不使用它时,但如果用户提供则可选
使用您生成的现有 SQL 查询,您可以简单地执行以下操作:
$bindParams = []; // array to hold existing parameter values for binding
foreach(['prov', 'city', 'addr', 'code', 'phone', 'phone_alt'] as $param) { // Check all possible parameters
if (!empty($$param)) { // If the parameter is not empty
$bindParams[] = $$param; // Add it to the array
}
}
$bindParams[] = $uid; // Add $uid to the array cause we always need it as the final value
$stmt = prepared_Query($con, $sql, $bindParams);
// Do whatever with $stmt