#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 по различным проблемам.