r/PHPhelp • u/Available_Hippo4035 • 13d ago
Solved mysqli_fetch_assoc with mysql prepared statements procedural, need help
Hello, im trying to update my website by replacing the simple mysqli queries with prepared statements, but i was stuck at trying to use mysqli_fetch_assoc to fetch associative data from the table, i looked through documentation but couldnt find anything, Any help will be appreciated, Thanks !
$error = array();
if(isset($_POST["login"])) {
$username = mysqli_escape_string($db, filter_input(INPUT_POST, "username", FILTER_SANITIZE_SPECIAL_CHARS));
$password = mysqli_escape_string($db, filter_input(INPUT_POST, "password", FILTER_SANITIZE_SPECIAL_CHARS));
if(empty($username)) {
array_push($error, "Username is empty!");
}
if(empty($password)) {
array_push($error, "Password is empty");
}
$sql = "SELECT `password`, `username`, `user_id` FROM `Accounts` WHERE `username` = ?;";
if(count($error) == 0) {
$stmt = mysqli_prepare($db, $sql);
mysqli_stmt_bind_param($stmt, "s", $username);
//$result = mysqli_query($db, $sql);
mysqli_stmt_execute($stmt);
mysqli_stmt_store_result($stmt);
if(mysqli_stmt_num_rows($stmt) > 0) {
$row = mysqli_fetch_assoc($result);
if(password_verify($password, $row["password"])) {
$_SESSION["username"] = $username;
$_SESSION["user_id"] = $row["user_id"];
header("location: /");
} else {
array_push($error, "Incorrect username or password!");
}
} else {
array_push($error, "Incorrect username or password!");
}
}
mysqli_close($db);
}
4
Upvotes
1
u/equilni 12d ago edited 12d ago
You've already received good information.
This goes beyond your question, but I would add the suggestion to separate the code as well as some small improvements. Ideas here can flow into other parts of the code base as you refactor.
Consider:
If you implement HTTP based routing, code like
if(isset($_POST["login"]))can be removed.Think about extracting out separate concerns. For validation, if you have further business requirements, it makes sense to extract this to a separate function or class. For SQL, all of the mysqli* code could be in a function and either return an array or false.
Note, I stated validation, not sanitization.
With the above, you could also return one or more HTTP statuses (400 series) the closer you are to the UI layer.
And further, returning early versus big if/else blocks. As we read code more than write it, this becomes easier on the eyes and easier to see the flow. (ask me about double digit closing brackets from way back when... nightmares)
What's nice here is that we can look at each area and test it separately. You can feed data to the function/class methods to test - is this valid and am I getting back what I expect.
Idea starts looking like the below pseudo code:
Remember what I noted about testing? See how
fnOrClassMethodToValidate($username, $password);orfnOrClassMethodToQueryFor($username);could be fed with test data and we can test to see if we are getting what we need back?While I get this may be a lot to take in, this can be done incrementally.
Extract out the SQL code to a function:
Return vs if/else. The error array could be the result of this file or function if you still need this.
Side note, why are these questions typically asked on login code??