«Создайте» подготовленный оператор SQL на основе пользовательских данных с помощью PHP - PullRequest
0 голосов
/ 20 сентября 2019

Этот вопрос немного сложно сформулировать, но в основном у меня есть форма.Это форма информации об учетной записи, где человек может изменить информацию, связанную с его учетной записью.Подвох в том, что вся форма отправляется с каждым необязательным вводом (оставьте ввод пустым для изменений) .Например, с помощью этой формы вы можете изменить свой город, адрес и телефон.Однако человек может выбрать только заполнить город, нажать отправить, и только эта информация будет обновлена, вся остальная информация останется прежней.

Это может иметь больше смысла с кодом в руке, вот PHP яиспользовать для выполнения этой задачи;Есть 4 строки с комментариями, которые содержат код, они были оставлены, поскольку они были попыткой ответить на мой собственный вопрос;они могут помочь объяснить, чего я пытаюсь достичь:

PHP

// 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 и основами программирования, это очень влажный код, где T больше не в два раза, а в 6 раз больше.В попытке решить эту проблему я создал массив, а затем foreach input, который был установлен;добавить имя столбца в этот массив.После завершения implode массив использует запятую.Наконец, создайте оператор SQL, используя этот развернутый массив.

Это выводит динамически построенный оператор SQL, основанный на любых заданных входных данных.Так что, если City и Address содержат данные, оператор будет выглядеть следующим образом:

$sql = "UPDATE _MAIN_meta SET meta_city = ?, meta_addr = ? WHERE meta_user = ?;";

Теперь у меня есть эта работа до этого момента, в зависимости от того, какие входные данные я заполнил, окончательный вывод SQL-оператора:именно то, что я хочу, чтобы это было.

Проблема ...

... У меня есть когда дело доходит до привязки этого оператора к переменным-переменным.Я не знаю, возможно ли вообще получить ALL установленных var-переменных в параметрах этой prepared_Query() функции, когда я не знаю, какие из них установлены.

Возможно, моя логика ошибочна, но я был так близок к тому, чтобы заставить это работать, я должен спросить, есть ли способ, которым я могу это сделать, или есть ли смысл делать это таким образом.Это имеет смысл для меня, но я уже делал несколько довольно неприятных черных дыр с помощью PHP.Я уверен, что есть кто-то с немного более здравым смыслом, чем я ... когда дело доходит до того, чтобы делать что-то подобное.

Поэтому мой вопрос, как я могу связать переменные с подготовленным оператором SQLкогда каждый из них не является обязательным.Есть ли способ не писать отдельное утверждение для каждого ввода?Или более короткий / более быстрый способ сделать это?

Эти вопросы SO похожи, но не отвечают на мой вопрос:

, динамически генерирующий оператор SQL на основе ввода формы пользователя

Динамический оператор SQL SELECT с PHP на основе пользовательских опций

Кажется, есть еще несколько вопросов, сформулированных так, но я не смог найтиНаглядный пример того, как кто-то пытается решить такую ​​же проблему.Это то, что заставляет меня думать, что моя логика как-то ошибочна.

Может кто-нибудь указать мне правильное направление, пожалуйста?

Примечание: я думаю, что я вставил все, что имеет отношение к вопросу, дайте мне знать, если что-то не понятно.

Ответы [ 3 ]

3 голосов
/ 20 сентября 2019

Оба других ответа почти хороши.

Ответ от @ 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'];
prepared_query("UPDATE _MAIN_meta SET $setStr WHERE main_user = ?", [$params]);

И ради бога, забудьте о переменных переменных.Для них нет абсолютно никакого варианта использования , но они могут нанести значительный вред .$_POST массив является отличным источником для ваших данных, больше ничего не нужно.

0 голосов
/ 20 сентября 2019

С помощью созданного вами существующего 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
0 голосов
/ 20 сентября 2019

Я думаю, я бы сделал это так:

$city = $_POST['city'];
$addr = $_POST['addr'];
$phone = $_POST['phone'];
$condition = $_POST['condition'];

$bindParams = [];
$query = "UPDATE _MAIN_meta SET ";

if(!empty($city)){
    $query .= "meta_city = ?, ";
    $bindParams[] = $city;
}
if(!empty($addr)){
    $query .= "meta_addr = ?, ";
    $bindParams[] = $addr;
}
if(!empty($phone)){
    $query .= "meta_phone = ?, ";
    $bindParams[] = $phone;
}

if(count($bindParams) == 0)
    die("Nothing to update");

$query = substr($query, 0, -2); //remove the ", " at the end
$query = " WHERE uid=? ";
$bindParams[] = $uid;

if(!empty($condition)){
    $query .= "AND condition = ?";
    $bindParams[] = $condition;
}
$stmt = $con->prepare($query);

//if you want to bind parameters one by one:
$i = 0;
foreach($bindParams as $param){
    $stmt->bindValue($i, $param, PDO::PARAM_STR);
    $i++;
}

//or:
$stmt->execute($bindParams);

Вы можете расширить массив и добавить имена параметров и типы, такие как PARAM_INT.
Также вам следует проверить и добавить WHERE только один раз, если необходимо, например, когда вы не используете его по умолчанию в запросе, но при необходимости, если пользователь предоставляет

...