This question already has an answer here:
Should I manually check for errors when calling "mysqli_stmt_prepare"?
(1 answer)
Closed 1 year ago.
I'm trying to make a registeration form using php and sql but i keep getting "mysqli_stmt object is not fully initialized" as an error message.
Registration.php file:
$sql = "INSERT INTO user_table ('user_name', 'user_email', 'user_password') VALUES (?, ?, ?)";
$stmt = mysqli_stmt_init($conn);
if (mysqli_stmt_prepare($stmt, $sql)){
header("location: ../signup.php?error=sqlerror");
exit();
} else {
//hashing password
$hashedPass = password_hash($password, PASSWORD_DEFAULT);
//inserting hashed password.
mysqli_stmt_bind_param($stmt, "sss", $username, $email, $hashedPass);
mysqli_stmt_execute($stmt);
header("location: ../signup.php?success=registered");
exit();
}
I think the problem is in this part (in the line number 8).
If we remove your if/else check and run everything, with the mysqli_stmt_prepare after the mysqli_stmt_init we get what we expect.
$stmt = mysqli_stmt_init($conn);
mysqli_stmt_prepare($stmt, $sql);
So the logic on your if seems like it needs a ! (meaning false). Try this alteration to your code block:
$sql = 'INSERT INTO user_table (user_name, user_email, user_password) VALUES (?, ?, ?)';
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("location: ../signup.php?error=sqlerror");
exit();
} else {
//hashing password
$hashedPass = password_hash($password, PASSWORD_DEFAULT);
//inserting hashed password.
mysqli_stmt_bind_param($stmt, 'sss', $username, $email, $hashedPass);
mysqli_stmt_execute($stmt);
header("location: ../signup.php?success=registered");
exit();
}
The above code worked in my test.
Related
I am attempting to create a user directory that's name is equal to the user's 'id' which is an auto-incremented column in my database. that will later be used to store text files for the user to access. But, Every time I run this I get an error because $row is null.
For context, This code is run right after a user is inserted into the database.
I've tried checking that $conn is valid and that $username is the correct username. However, when I run createUserDir on an existing user everything works fine.
Code for creating a user (works fine but thought I would show the placement of function call):
function createUser($conn, $email, $username, $pwd) {
$sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?);";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("location: ../register.php?error=stmtfailure");
exit();
}
$hashpwd = password_hash($pwd, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, "sss", $email, $hashpwd, $username);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
createUserDir($conn, $username);
header("location: ../login.php?error=none");
exit();
}
Creates a user directory:
function createUserDir($conn, $username) {
$sql = "SELECT id FROM users WHERE username = ?;";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("location: ../register.php?error=stmtfailure");
exit();
}
mysqli_stmt_bind_param($stmt, "s", $username);
mysqli_stmt_execute($stmt);
$stmtResult = mysqli_stmt_get_result($stmt);
$row = mysqli_fetch_assoc($stmtResult);
$uid = $row['id'];
mysqli_stmt_close($stmt);
if(mkdir("../data/users/$uid")) {
die('Failed to create user directory.');
}
}
while creating a record add some text inside of the column, like "NA" so it won't return an error and later update values in last, using $last_id = $conn->insert_id;
might sound silly but might be it will work
Having this code:
$sql = "SELECT * FROM users WHERE user_login=?;";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
die(mysqli_error($conn));
} else {
mysqli_stmt_bind_param($stmt, 's', $login);
mysqli_stmt_execute($stmt);
mysqli_store_result($conn);
$resultCheck = mysqli_stmt_num_rows($stmt);
//err == login name is already taken
if ($resultCheck > 0) {
die("login is taken");
} else {
$sql = "INSERT INTO users(user_login, user_email, user_pwd) VALUES (?, ?, ?);";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
die(mysqli_error($conn));
} else {
$hashedPwd = password_hash($pwd, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, 'sss', $login, $email, $hashedPwd);
mysqli_stmt_execute($stmt);
}
// insert_usertodb($conn, $login, $email, $pwd);
}
}
works fine (`e.g. the part where is user inserted does not gives any mysqli error), however, if I tried to use a function, where the user is inserted:
function insert_usertodb($conn, $user_login, $user_email, $user_pwd)
{
$sql = "INSERT INTO users(user_login, user_email, user_pwd) VALUES (?, ?, ?);";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) { // <-- this is where the error happens
// err_signup('sqlierror', '', '');
die('sqlierror: ' . mysqli_error($conn));
} else {
//hash password
$hashedPwd = password_hash($user_pwd, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, 'sss', $user_login, $user_email, $hashedPwd);
mysqli_stmt_execute($stmt);
// header("Location: ../signup.php?signup=success");
}
}
And use it instead of the part, where the user is inserted (after else branch -> the function is commented at the end), the mysqli generates error:
Commands out of sync; you can't run this command now
Is there any reason, why the function with identical code (like literally copied the part (where is the insertion) and just change the variables name to be the argument that function) generates the out-of-sync error? and the code without the func doesn't?
This is because you used a wrong function here mysqli_store_result($conn);. You should have used mysqli_stmt_store_result($stmt); instead. This means that your code is not working as you wanted it to and the check for existence is broken. This is why it is a terrible idea to use mysqli_stmt_num_rows().
The reason why it works when it is not in the function is that you call the destructor on the $stmt object when you assign it a different value in $stmt = mysqli_stmt_init($conn);. When a destructor is called it will fetch all results in the background to "clean" the wire.
If it is not too late consider using PDO instead. It is simpler and you won't be making such mistakes so often. The code which you have written with mysqli is too verbose. You don't need most of it. This would be so much easier with PDO.
$username = $_POST['uid'];
$email = $_POST['mail'];
$password = $_POST['pwd'];
$passwordRepeat = $_POST['pwd-repeat'];
$date = $_POST['date2'];
$stream = $_POST['relationship'];
$sql1 = "INSERT INTO users (uidUsers, emailUsers, pwdUsers, relationship) VALUES (?, ?, ?, ?);";
$sql2 = "INSERT INTO Family1 (username, application_filed, relationship) VALUES (?, ?, ?);";
$sql3 = "INSERT INTO Family2 (username, application_filed, relationship) VALUES (?, ?, ?);";
mysqli_query($sql1, $conn);
mysqli_query($sql2, $conn);
mysqli_query($sql3, $conn);
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql2)) {
header("Location: ../signup.php?error=sqlerror");
exit();
}
else {
mysqli_stmt_bind_param($stmt, "sss", $username, $date, $stream);
$result = mysqli_stmt_get_result($stmt);
if ($row = mysqli_fetch_assoc($result))
($username==$_SESSION['uid'] and $stream =='nursing');
mysqli_stmt_execute($stmt);
}
if (!mysqli_stmt_prepare($stmt, $sql3)) {
header("Location: ../signup.php?error=sqlerror");
exit();
}
else {
mysqli_stmt_bind_param($stmt, "sss", $username, $date, $stream);
$result = mysqli_stmt_get_result($stmt);
if ($row = mysqli_fetch_assoc($result))
($username==$_SESSION['uid'] and $stream =='doctoral');
mysqli_stmt_execute($stmt);
}
if (!mysqli_stmt_prepare($stmt, $sql1)) {
header("Location: ../signup.php?error=sqlerror");
exit();
}
if (!mysqli_stmt_prepare($stmt, $sql1)) {
header("Location: ../signup.php?error=sqlerror");
exit();
}
else {
$hashedPwd = password_hash($password, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, "ssss", $username, $email, hashedPwd,$stream);
mysqli_stmt_execute($stmt);
header("Location: ../signup.php?signup=success");
exit();
/////////////New Code////////////////
$username = $_POST['uid'];
$email = $_POST['mail'];
$password = $_POST['pwd'];
$passwordRepeat = $_POST['pwd-repeat'];
$date = $_POST['date2'];
$stream = $_POST['relationship'];
$sql1 = "INSERT INTO users (uidUsers, emailUsers, pwdUsers, relationship) VALUES (?, ?, ?, ?);";
$sql2 = "INSERT INTO Family1 (username, application_filed, relationship) VALUES (?, ?, ?);";
$sql3 = "INSERT INTO Family2 (username, application_filed, relationship) VALUES (?, ?, ?);";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql2)) {
header("Location: ../signup.php?error=sqlerror");
exit();
} else if ($username==$_SESSION['uid'] && $stream =='nursing') {
mysqli_stmt_bind_param($stmt, "sss", $username, $date, $stream);
mysqli_stmt_execute($stmt);
}
if (!mysqli_stmt_prepare($stmt, $sql3)) {
header("Location: ../signup.php?error=sqlerror");
exit();
}
else if ($username==$_SESSION['uid'] && $stream =='doctoral') {
mysqli_stmt_bind_param($stmt, "sss", $username, $date, $stream);
mysqli_stmt_execute($stmt);
}
if (!mysqli_stmt_prepare($stmt, $sql1)) {
header("Location: ../signup.php?error=sqlerror");
exit();
}
else {
$hashedPwd = password_hash($password, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, "ssss", $username, $email, $hashedPwd, $stream);
mysqli_stmt_execute($stmt);
header("Location: ../signup.php?signup=success");
exit();
}
I was wondering if someone could point me in the right direction. I have this code. They idea I had behind it is to insert values into different tables depending on variables being passed.
So when user fills out a form and selects $stream="nursing" I want results to go to table 'users' and 'Family1', but not 'Family2' table. and if user selects $stream='doctoral' results should go to table 'users' and 'Family2', and not go to 'Family1'
But with my query I get results go to both table and also users table. And there is no restriction to what users selects, variable $stream being passed no matter what it is.
Is this the wrong way to go here? Did I completely mess up the logic?
For one thing, the mysqli_query() calls at the top will try to run the queries and will fail, since it has no understanding of the ? placeholders and you have the $conn and $sqlX variables the wrong way around.
But aside from that, let me fix the indentation for you so you can see what's actually happening for one of your statements:
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql2)) {
header("Location: ../signup.php?error=sqlerror");
exit();
} else {
mysqli_stmt_bind_param($stmt, "sss", $username, $date, $stream);
$result = mysqli_stmt_get_result($stmt);
if ($row = mysqli_fetch_assoc($result))
($username==$_SESSION['uid'] and $stream =='nursing');
mysqli_stmt_execute($stmt);
}
Do you see what's happening here?
$sql2 is an INSERT query. If you were able to prepare that statement you try to get the result before the query is even executed. If you manage to retrieve a row of data from that result (which you can't since an INSERT query does not return any records), you then do a check on $username and $stream that has no effect. The call to execute the prepared statement is executed regardless of whether or not you managed to get anything from $result.
All your statements have the same problems, so I'll only fix this one.
Here's what I changed:
The whole $result step seemed unnecessary, so I removed it.
I replaced and with && because of my personal preference. There was once a reason why it became my preference, but I forget. It's mostly for consistency between programming languages, since many languages use && and only a few use and.
Since there's no point in binding params to a statement you're not planning to execute, I moved that into the if-statement.
Since I now ended up with an else { if { ... } } construction, I simplified that down to an else if { ... } for cleaner code.
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql2)) {
header("Location: ../signup.php?error=sqlerror");
exit();
} else if ($username==$_SESSION['uid'] && $stream =='nursing') {
mysqli_stmt_bind_param($stmt, "sss", $username, $date, $stream);
mysqli_stmt_execute($stmt);
}
Now, the query $sql2 is only executed if the $username matches the current uid from the session and the user selected the nursing stream.
I have a form that will insert users input from a form into database, I want to store the email in a separate table to the users.
So I want the email in an accounts table and then the username and password in a users table. For anyone wondering why, the application I want to build will allow users to create a new user after dying but can have stuff stored in the accounts that will be carried over.
I tried working with multiple of the same code but just gets too much and get lost in it all. There must be an easier way to do than multiple copied of stretched code.
$sql = "SELECT user_name FROM users WHERE user_name=?";
$stmt = mysqli_stmt_init($conn);
if(!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: ../register.php?error=Sql_Error");
exit();
} else {
mysqli_stmt_bind_param($stmt, "s", $character);
mysqli_stmt_execute($stmt);
mysqli_stmt_store_result($stmt);
$resultCheck = mysqli_stmt_num_rows($stmt);
if ($resultCheck > 0) {
header("Location: ../register.php?error=CharacterTaken&email=".$emailAddress);
exit();
} else {
$sql = "INSERT INTO users (user_name, user_email, user_password) VALUES (?, ?, ?)";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: ../register.php?error=Sql_Error");
exit;
} else {
$hashedPwd = password_hash($password, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, "sss", $character, $emailAddress, $hashedPwd);
mysqli_stmt_execute($stmt);
header("Location: ../register.php?success=Account Created.");
If you wish to insert separate data in separate tables I suggest you just to use 2 separate INSERT queries.
As there is one part of your code doing it already, the easiest way is to adjust it and duplicate it:
Replace this part of code
$sql = "INSERT INTO users (user_name, user_email, user_password) VALUES (?, ?, ?)";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: ../register.php?error=Sql_Error");
exit;
} else {
$hashedPwd = password_hash($password, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, "sss", $character, $emailAddress, $hashedPwd);
mysqli_stmt_execute($stmt);
With this:
$sql = "INSERT INTO users (user_name, user_password) VALUES (?, ?)";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: ../register.php?error=Sql_Error");
exit;
} else {
$hashedPwd = password_hash($password, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, "ss", $character, $hashedPwd);
mysqli_stmt_execute($stmt);
$sql = "INSERT INTO accounts (user_email) VALUES (?)";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: ../register.php?error=Sql_Error");
exit;
} else {
mysqli_stmt_bind_param($stmt, "s", $emailAddress);
mysqli_stmt_execute($stmt);
I have a signup form on my website and the following code should run whenever a new user signs up:
$sql = "SELECT * FROM users WHERE uidUsers=?;";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt)) {
header("Location: ../signup.php?error=sqlerror");
exit();
}
else {
mysqli_stmt_bind_param($stmt, "s", $username);
mysqli_stmt_execute($stmt);
$resultCheck = mysqli_stmt_num_rows($stmt);
if ($resultCheck > 0) {
header("Location: ../signup.php?error=usertaken");
exit();
}
else {
$hashedPwd = password_hash(PASSWORD_DEFAULT, $password);
$sql = "INSERT INTO users (`uidUsers`, `pwdUsers`, `phraseUsers`) VALUES(?,
?, ?)";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt)) {
header("Location: ../signup.php?error=sqlerror");
exit();
}
else {
mysqli_stmt_bind_param($stmt, "sss", $username, $hashedPwd,
$securityphrase);
mysqli_stmt_execute($stmt);
header("Location: ../login.php?signup=success");
exit();
}
The !mysqli_stmt_prepare error handler is triggered when it shouldn't be given the database circumstance, as well as the correct INSERT statement. Therefore I don't understand why it's triggered and I'm asking why?
There is a similar question here on Stack Overflow
Thank you for your help, the problems where the password_hash order, it should be like this password_hash($var, PASSWORD_DEFAULT);. The second mistake I made was not including my $sql statements in the mysqli_stmt_prepare, it should be like this !mysqli_stmt_prepare($stmt, $sql).