In my last question people said that I need to use prepared statements to avoid SQL injection.
I'm changing the previous SQL's now to prepared statements, as y'all wanted.
The thing is, it submits the settings, this part:
$stmt_setsettings = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt_setsettings, $usersettings_sql)) {
array_push($errors, "Safe SQL failed, could not insert settings. Contact the helpdesk.");
} else {
mysqli_stmt_bind_param($stmt_setsettings, "sssss", $email_show, $fname_show, $lname_show, $private_account, $profile_style);
mysqli_stmt_execute($stmt_setsettings);
}
But it submits none of the actual info I need (like the username, firstname, ...)
Also, at the end of the code below it should redirect to the new profile, normally if this feels it should display "Something went wrong, refer to the helpcenter. (SE100)" but it like refreshes the sign up page and throws no error, while there is an error: the not submitting info!
I tried searching up similar questions or fixes but nothing useful found.
Can you check out the following code and let me know what is the deal with the not submitting values? Thanks!
// Finally, register user if there are no errors in the form
if (count($errors) == 0) {
$password = md5($password_1); // Encrypt the password before saving in the database
$user_ip = $_SERVER['REMOTE_ADDR']; // Getting the IP of the user
$bio = $config['default-bio']; // Setting default biography
$profileimg = $config['default-profileimg']; // Setting default profile image
$timestamp = date('d.m.Y'); // Defining the current date
$activity = "on"; // Defining which state the user profile is in, online
$userdata_sql = "INSERT INTO users (username, bio, activity, profileimg, regdate, email, password, firstname, lastname, gender, birthday, country, ip)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
$usersettings_sql = "INSERT INTO usersettings (show_email, show_fname, show_lname, private_acc, profile_style)
VALUES (?, ?, ?, ?, ?)";
$stmt_signup = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt_signup, $userdata_sql)) {
array_push($errors, "Safe SQL failed, could not sign up. Contact the helpdesk.");
} else {
mysqli_stmt_bind_param($stmt_signup, "sssssssssssss", $username, $bio, $activity, $profileimg, $regdate, $email, $password, $fname, $lname, $sex, $bday, $country, $user_ip);
mysqli_stmt_execute($stmt_signup);
}
$stmt_setsettings = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt_setsettings, $usersettings_sql)) {
array_push($errors, "Safe SQL failed, could not insert settings. Contact the helpdesk.");
} else {
mysqli_stmt_bind_param($stmt_setsettings, "sssss", $email_show, $fname_show, $lname_show, $private_account, $profile_style);
mysqli_stmt_execute($stmt_setsettings);
}
session_regenerate_id();
$_SESSION['username'] = $username;
$_SESSION['loggedin'] = true;
// Generate user id
$generateid_sql = "SELECT id FROM users WHERE username=? ORDER BY id";
$stmt_generateid = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt_generateid, $generateid_sql)) {
array_push($errors, "Safe SQL failed, could not generate a new ID. Contact the helpdesk.");
} else {
mysqli_stmt_bind_param($stmt_generateid, "s", $username);
mysqli_stmt_execute($stmt_generateid);
$generateid_result = mysqli_stmt_get_result($stmt_generateid);
}
while ($id = mysqli_fetch_assoc($generateid_result)) {
if ($id['username'] <= 0) { // Checking if the user id is a valid id (not below or equal to 0), and if not, displaying a critical error
array_push($errors, "Something went wrong whilst signing up, please refer to the helpcenter. (SE100)");
}
if ($id['username'] > 0) { // Redirecting the user to his or her profile if it is a valid id
header('location: /content/users/profile?id=' . $id['username'] . '');
}
}
}
}
First off, PLEASE don't ever store passwords like this:
$password = md5($password_1); // <-- Totally insecure
Instead use the built-in password_hash() and password_verify() functions. See https://www.php.net/manual/en/faq.passwords.php for a good overview of why md5() is not secure and examples how to handle password storage correctly.
Also, I'd recommend pulling the user out of the database and validating the password, BEFORE setting $_SESSION['loggedin'] = true.
Regarding your question, I'd recommend adding some additional error handling and result checking around your calls to $conn->prepare() and $stmt->bind_param. See mysqli_stmt_execute() does not execute the prepared query for examples of how to check $stmt->errors.
Another general recommendation is checking $stmt->affected_rows to see if your insert statements are actually being executed as you expect. Your inserts should each be affecting 1 row.
Lastly, turning on the MySQL query log can be a great troubleshooting tool: How to show the last queries executed on MySQL? . Are all the SQL queries in your code showing up in the log? Try running the queries manually and see if the results look right.
// Finally, register user if there are no errors in the form
if (count($errors) == 0) {
$password = md5($password_1); // Encrypt the password before saving in the database
$user_ip = $_SERVER['REMOTE_ADDR']; // Getting the IP of the user
$bio = $config['default-bio']; // Setting default biography
$profileimg = $config['default-profileimg']; // Setting default profile image
$timestamp = date('d.m.Y'); // Defining the current date
$activity = "on"; // Defening wich state the user profile is in, online
$userdata_sql = "INSERT INTO users (`username`, `bio`, `activity`, `profileimg`, `regdate`, `email`, `password`, `firstname`, `lastname`, `gender`, `birthday`, `country`, `ip`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
$usersettings_sql = "INSERT INTO usersettings (`show_email`, `show_fname`, `show_lname`, `private_acc`, `profile_style`)
VALUES (?, ?, ?, ?, ?)";
$stmt_signup = $conn->prepare($userdata_sql);
$stmt_signup->bind_param("sssssssssssss", $username, $bio, $activity, $profileimg, $timestamp, $email, $password, $fname, $lname, $sex, $bday, $country, $user_ip);
if(!$stmt_signup->execute()){
array_push($errors,mysqli_error($conn));
}
$stmt_setsettings=$conn->prepare($usersettings_sql);
$stmt_setsettings->bind_param("sssss", $email_show, $fname_show, $lname_show, $private_account, $profile_style);
if(!$stmt_setsettings->execute()){
array_push($errors,mysqli_error($conn));
}
session_regenerate_id();
$_SESSION['username'] = $username;
$_SESSION['loggedin'] = true;
// Generate user id
$generateid_sql = "SELECT `id`,`username` FROM `users` WHERE `username`=? ORDER BY `id` limit 1";
$stmt_generateid=$conn->prepare($generateid_sql);
$stmt->generateid->bind_param("s", $username);
if(!$stmt_generateid->execute()){
array_push($errors,mysqli_error($conn));
}else{
$generateid_result = $stmt_generateid->get_result();
}
$username_assoc = mysqli_fetch_assoc($generateid_result);
if ($username_assoc['id'] > 0) {
// Redirecting the user to his or her profile if it is a valid id
header('location: /content/users/profile?id=' . $username_assoc['username'] . '');
}else{
array_push($errors, "Something went wrong whilst signing up, please refer to the helpcenter. (SE100)");
}
}
How can I troubleshoot further? I have 3 styles of querying. This is for a fetchType = 'single' ( single row that is) and a populated parameterArray
public function query($fetchType, $queryType, $parameterArray=null)
{
$query=$this->sql_array[$queryType];
if($parameterArray==null)
{
$pdoStatement = $this->db_one->query($query);
$results = $pdoStatement->fetchAll(PDO::FETCH_ASSOC);
return $results;
}
$this->db_one->quote($query);
$pdoStatement = $this->db_one->prepare($query);
$results = $pdoStatement->execute($parameterArray);
if($fetchType=='single')
{
$results = $pdoStatement->fetch(PDO::FETCH_ASSOC);
}
else if($fetchType=='multiple')
{
$results = $pdoStatement->fetchAll(PDO::FETCH_ASSOC);
}
return $results;
}
My results is coming back false and I see no data in the sql table.
I verified that the queryType exists in the lookup table and that other queries are working.
Here is the actual query. I inserted new lines to make readable.
"signup_insert" =>
"INSERT INTO credentials
(h_token, h_file, h_pass, email, name, picture, privacy)
VALUES (?, ?, ?, ?, ?, ?, ?)"
Here is the debug code I created:
$pipe['debug_h_token']=$h_token;
$pipe['debug_h_file']=$h_file;
$pipe['debug_h_pass']=$h_pass;
$pipe['debug_email']=$this->TO->get('email');
$pipe['debug_name']=$this->TO->get('name');
$pipe['debug_picture']=$picture;
$pipe['debug_privacy']=$privacy;
$test = $this->DBO->query('single', 'signup_insert', array(
$h_token,
$h_file,
$h_pass,
$this->TO->get('email'),
$this->TO->get('name'),
$picture,
$privacy
));
$pipe['debug_test'] = $test;
So I've been trying to find an answer but I don't think there is one that is specified to what I am trying to do. I will start with my sample of code
file.php
$q = "INSERT INTO ".PORTAL_DB.".resource_file (company__id, rf_category__id, title, file_name, description, path, upload_by, has_quiz)
SELECT ?, ?, ?, CONCAT(MAX(id)+1, '.', '$extension'), ?, ?, ?, ? FROM ".PORTAL_DB.".resource_file";
$stmt = $CONN->prepare($q);
$filename = 0;
$resource_file__id = 0;
if($stmt->execute(array($company__id, $rf_category__id, $title, $description, "assets/$uploadFolder/", USER, $has_quiz))){
$filename = $CONN->lastInsertId();
$resource_file__id = $filename;
}
if(!empty($quiz)){
$passing_score = $quiz->passing_score;
if(!is_numeric($passing_score) or ($passing_score < 0) or $passing_score > 100){
$CONN->rollback();
throw new Exception("Invalid passing score value for quiz, please fix");
}
$q = "INSERT INTO ".PORTAL_DB.".rf_quiz (resource_file__id, passing_score)
VALUES(?, ?)";
$stmt = $CONN->prepare($q);
$rf_quiz__id = 0;
$stmt->execute(array($resource_file__id, $passing_score));
print_r($CONN->lastInsertId);
exit;
$question_ids = array();
foreach($quiz as $qz){
$question = $qz->question;
//print_r($qz);
$q = "INSERT INTO ".PORTAL_DB.".rf_quiz_question (rf_quiz__id, question)
VALUES(?, ?)";
$stmt = $CONN->prepare($q);
if($stmt->execute(array($rf_quiz__id, $question))){
array_push($question_ids, $CONN->lastInsertId);
}
}
//print_r($question_ids);
exit; // using this for testing only
}
explanation
The above code is called after $CONN->beginTransaction() so that I can manage errors easier. From what I understand you can call the stamtement $CONN->lastInsertId() multiple times without issue, however I can get the first id which is stored under the variable $resource_fild__id then when we go down to the $rf_quiz__id variable, even if the call is successful, I get nothing and it causes an error. I want to be able to do all of this in one transaction for the ease of the coding process and organization.
I hope someone can point me in the right direction, or at least be able to tell me what I am doing wrong so that I can find a fast solution!
Thank you for all help in advance.
I'm wondering how to insert multiple values into a database.
Below is my idea, however nothing is being added to the database.
I return the variables above (email, serial, title) successfully. And i also connect to the database successfully.
The values just don't add to the database.
I get the values from an iOS device and send _POST them.
$email = $_POST['email'];
$serial = $_POST['serial'];
$title = $_POST['title'];
After i get the values by using the above code. I use echo to ensure they have values.
Now I try to add them to the database:
//Query Check
$assessorEmail = mysqli_query($connection, "SELECT ace_id,email_address FROM assessorID WHERE email_address = '$email'");
if (mysqli_num_rows($assessorEmail) == 0) {
echo " Its go time add it to the databse.";
//It is unqiue so add it to the database
mysqli_query($connection,"INSERT INTO assessorID (email_address, serial_code, title)
VALUES ('$email','$serial','$title')");
} else {
die(UnregisteredAssessor . ". Already Exists");
}
Any ideas ?
Since you're using mysqli, I'd instead do a prepared statement
if($stmt = mysqli_prepare($connection, "INSERT INTO assessorID (email_adress, serial_code, title) VALUES (?, ?, ?)"))
{
mysqli_stmt_bind_param($stmt, "sss", $email, $serial, $title);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
}
This is of course using procedural style as you did above. This will ensure it's a safe entry you're making as well.
I was wondering if someone could help me.
Im trying to integrate some code into my application, the code that i need to integrate is written with PDO statements and i have no idea how it goes.
I was wondering if someone could help me convert it.
The code is as follows
$sql = "insert into message2 (mid, seq, created_on_ip, created_by, body) values (?, ?, ?, ?, ?)";
$args = array($mid, $seq, '1.2.2.1', $currentUser, $body);
$stmt = $PDO->prepare($sql);
$stmt->execute($args);
if (empty($mid)) {
$mid = $PDO->lastInsertId();
}
$insertSql = "insert into message2_recips values ";
$holders = array();
$params = array();
foreach ($rows as $row) {
$holders[] = "(?, ?, ?, ?)";
$params[] = $mid;
$params[] = $seq;
$params[] = $row['uid'];
$params[] = $row['uid'] == $currentUser ? 'A' : 'N';
}
$insertSql .= implode(',', $holders);
$stmt = $PDO->prepare($insertSql);
$stmt->execute($params);
You shoudl use PDO unles for some technical reason you cant. If you dont know it, learn it. Maybe this will get you started:
/*
This the actual SQL query the "?" will be replaced with the values, and escaped accordingly
- ie. you dont need to use the equiv of mysql_real_escape_string - its going to do it
autmatically
*/
$sql = "insert into message2 (mid, seq, created_on_ip, created_by, body) values (?, ?, ?, ?, ?)";
// these are the values that will replace the ?
$args = array($mid, $seq, '1.2.2.1', $currentUser, $body);
// create a prepared statement object
$stmt = $PDO->prepare($sql);
// execute the statement with $args passed in to be used in place of the ?
// so the final query looks something like:
// insert into message2 (mid, seq, created_on_ip, created_by, body) values ($mid, $seq, 1.2.2.1, $currentUser, $body)
$stmt->execute($args);
if (empty($mid)) {
// $mid id is the value of the primary key for the last insert
$mid = $PDO->lastInsertId();
}
// create the first part of another query
$insertSql = "insert into message2_recips values ";
// an array for placeholders - ie. ? in the unprepared sql string
$holders = array();
// array for the params we will pass in as values to be substituted for the ?
$params = array();
// im not sure what the $rows are, but it looks like what we will do is loop
// over a recordset of related rows and do additional inserts based upon them
foreach ($rows as $row) {
// add a place holder string for this row
$holders[] = "(?, ?, ?, ?)";
// assign params
$params[] = $mid;
$params[] = $seq;
$params[] = $row['uid'];
$params[] = $row['uid'] == $currentUser ? 'A' : 'N';
}
// modify the query string to have additional place holders
// so if we have 3 rows the query will look like this:
// insert into message2_recips values (?, ?, ?, ?),(?, ?, ?, ?),(?, ?, ?, ?)
$insertSql .= implode(',', $holders);
// create a prepared statment
$stmt = $PDO->prepare($insertSql);
// execute the statement with the params
$stmt->execute($params);
PDO really is better. It has the same functionality as MySQLi but with a consistent interface across DB drivers (ie. as long as your SQL is compliant with a different database you can theoretically use the exact same php code with mysql, sqlite, postresql, etc.) AND much better parameter binding for prepared statements. Since you shouldnt be using the mysql extension any way, and MySQLi is more cumbersome to work with than PDO its really a no-brainer unless you specifically have to support an older version of PHP.