PHP | SQL — сбой mysqli_stmt_prepare и подключение к базе данных

#php #mysql

#php #mysql

Вопрос:

Я пытаюсь выполнить параметризованный запрос, чтобы обновить некоторые данные в базе данных.

Проблема в том, что сбой mysqli_stmt_prepare. Требование используется для подключения к базе данных.

 require 'includes/dbInclude.php';
if ($codeQuery > 0){
    $confirmationUsername = $_GET['confirmationUsername'];
    $active = "active";
    $noCode = "";
    $insertSql = "UPDATE users SET accountStatus = ? WHERE username = $confirmationUsername";
    $insertSql2 = "UPDATE users SET confirmationCode = ? WHERE username = $confirmationUsername";
    $statement = mysqli_stmt_init($connection);
    $statement2 = mysqli_stmt_init($connection);
    if (!mysqli_stmt_prepare($statement, $insertSql)){
        header("Location: registerComplete.php?error=sqlError1");
        exit();
    }
    elseif (!mysqli_stmt_prepare($statement2, $insertSql2)){
        header("Location: registerComplete.php?error=sqlError2");
        exit();
    }
    else{
        mysqli_stmt_bind_param($statement, "s", $active);
        mysqli_stmt_execute($statement);
        mysqli_stmt_bind_param($statement2, "s", $noCode);
        mysqli_stmt_execute($statement2);
    }
}
 

dbInclude.php содержит:

 <?php

//connection variables
$serverName = "localhost";
$dbUsername = "root";
$dbPassword = "";
$dbName = "ecglive";

//connection
$connection = mysqli_connect($serverName, $dbUsername, $dbPassword, $dbName);

//connection error
if(!$connection){
    die("There was an error connceting to the database: " . mysqli_connect_error());
}
 

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

Он всегда выдает первую ошибку if, где указано sqlError1, и если я ее удалю, то она перейдет к sqlError2.

Я допустил какую-либо ошибку?

Комментарии:

1. вы упускаете суть подготовленного оператора, напрямую внедряя переменную в оператор sql — что еще хуже, переменная является переменной GET и никоим образом не очищается

2. неэкранированная и встроенная переменная также должна быть в кавычках, поскольку предположительно это строка

3. Я в замешательстве. Я читал о подготовленных операторах, и там, где я читал, было написано что-то вроде этого. Что мне тогда делать?

4. Ключевым моментом здесь является подготовка всех значений данных, а не только некоторых из них. Как правило, не вводите $ строки запроса. Вы должны даже рассмотреть возможность использования одинарных кавычек для описания запросов, чтобы у вас не возникло соблазна интерполировать эти строки.

5. Примечание: объектно-ориентированный интерфейс to mysqli значительно менее подробный, что упрощает чтение и аудит кода, и его нелегко спутать с устаревшим mysql_query интерфейсом, где отсутствие одного i может вызвать проблемы. Пример: $db = new mysqli(…) и $db->prepare("…") процедурный интерфейс в значительной степени является артефактом эпохи PHP 4, когда mysqli был представлен API, и его не следует использовать в новом коде.

Ответ №1:

Вам необходимо привязать username дополнение к accountstatus , чтобы помочь смягчить внедрение SQL.

 require 'includes/dbInclude.php';

if ($codeQuery > 0){

    $confirmationUsername = $_GET['confirmationUsername'];
    $active = "active";
    $noCode = "";

    $insertSql = "UPDATE users SET accountStatus = ? WHERE username = ?";
    $insertSql2 = "UPDATE users SET confirmationCode = ? WHERE username = ?";

    $statement = mysqli_stmt_init($connection);
    $statement2 = mysqli_stmt_init($connection);


    if (!mysqli_stmt_prepare($statement, $insertSql)){
        exit(header("Location: registerComplete.php?error=sqlError1") );
    } elseif (!mysqli_stmt_prepare($statement2, $insertSql2)){
        exit(header("Location: registerComplete.php?error=sqlError2") );
    } else{

        mysqli_stmt_bind_param($statement, "ss", $active,$confirmationUsername);
        mysqli_stmt_execute($statement);

        mysqli_stmt_bind_param($statement2, "ss", $noCode,$confirmationUsername);
        mysqli_stmt_execute($statement2);
    }
}
 

Комментарии:

1. Он username не был экранирован, так что это был недопустимый SQL. Сообщение об ошибке, которое вы проигнорировали, содержало подробные сведения.

Ответ №2:

Этот код использует очень странный стиль, и он гораздо более подробный, чем необходимо. Вот более минимальная форма того же:

 require 'includes/dbInclude.php';

// Enable exception reporting
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

if ($codeQuery > 0) {
    try {
      // Prepare one query that sets both properties.
      $stmt = $connection->prepare('UPDATE users SET accountStatus=?,confirmationCode=? WHERE username=?');

      // Bind parameters directly form the source, no variables needed.
      $stmt->bind_param('ss', 'active', '', $_GET['confirmationUsername']);

      // Attempt to execute
      $stmt->execute();
    }
    catch (Exception $e) {
      // Error handling here...
      header("Location: registerComplete.php?error=sqlError2");
      exit();
    }
}
 

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

При этом, если это система регистрации для какого-то уровня управления доступом пользователей, и это не академический проект, вам следует прекратить работу над этим кодом, прежде чем создавать огромный беспорядок. Написать свой собственный уровень управления доступом непросто, и есть много возможностей сделать это неправильно.

Любая современная платформа разработки, такая как Laravel, поставляется со встроенной надежной системой аутентификации. Это решаемая проблема, и вам не нужно пытаться заново изобретать колесо.

По крайней мере, следуйте рекомендуемым рекомендациям по безопасности и никогда не храните пароли в виде обычного текста или слабого хэша, такого как SHA1 или MD5.

Комментарии:

1. Спасибо за ссылку. Кроме того, что вы имеете в виду, говоря о том, чтобы быть многословным? В вашем коде вы просто опустили некоторый код, который мне был нужен, например, 2-й оператор. Также можете ли вы сказать мне, почему, по вашему мнению, лучше или действительно лучше для пользовательского ооп, помимо путаницы с msql? Кроме того, я на самом деле установил систему безопасности, так что, если я все сделал правильно, в чем проблема с созданием моей собственной системы аутентификации?, чему я научился и даже не знал о laravel. Каковы возможные проблемы, если я все сделал правильно и безопасно? Наконец, это для моего последнего школьного проекта.

2. Что означает «я действительно установил систему безопасности»? Обычно это ошибочное предположение. Что касается запросов, я объединил оба ваших оператора в один оператор, так как вы можете задать два значения столбца одним запросом. Нет необходимости в двух запросах, и вам не нужно «инициализировать» каждый оператор перед его подготовкой, prepare() функция выполняет обе эти вещи за один шаг.

3. Если это просто академический проект, то я надеюсь, что вы многому научитесь, это и есть цель здесь. Я просто выражаю предостережение, потому что развертывание вашего исходного кода может подвергнуть вас и ваших пользователей серьезным рискам для безопасности. Чтобы узнать больше о веб-безопасности, ознакомьтесь с серией документов OWASP по различным проблемам.