PHP PDO Reset User Password Form Saving Incorrectly?

I created a PHP form in an application that can change user settings. Two of the fields in the form change the user’s password:

Here is an image of the form:

here is the code (HTML):

<form action="api/users/edit.php" method="post">
			<input type="hidden" class="form-control" id="id" name="id" placeholder="" value="<?php print($rowUser['id']); ?>" maxlength="255" autocomplete="off" readonly/>	
		<div class="form-group">
			<label for="role_id">User Status</label>
			<!-- <input type="text" class="form-control" id="role_id" name="role_id" placeholder="" value="<?php print($rowUser['role_id']); ?>" maxlength="255" autocomplete="off" /> -->
			<?php
			
			if($_SESSION['id'] == $rowUser['id']) {
				echo '<select disabled class="form-control" id="status" name="status">
				<option selected value="1">Active</option>
				<option value="0">Inactive</option>
			</select>';
				echo '<p style="color: #a40000;">The user status cannot be changed</p>';
			} else {
			if($rowUser['status'] === '1') {
				echo '<select class="form-control" id="status" name="status">
				<option selected value="1">Active</option>
				<option value="0">Inactive</option>
			</select>';
			} elseif ($rowUser['status'] === '0') {
				echo '<select class="form-control" id="status" name="status">
				<option value="1">Active</option>
				<option selected value="0">Inactive</option>
			</select>';
			}
			}
			
			?>
		</div>	
		<div class="form-group">
			<label for="role_id">User Role</label>
			<!-- <input type="text" class="form-control" id="role_id" name="role_id" placeholder="" value="<?php print($rowUser['role_id']); ?>" maxlength="255" autocomplete="off" /> -->
			<?php
			
			if($_SESSION['id'] == $rowUser['id']) {
				echo '<select disabled class="form-control" id="role_id" name="role_id">
				<option selected value="1">Administrator</option>
				<option value="2">Operator</option>
			</select>';
			echo '<p style="color: #a40000;">The user role cannot be changed</p>';
			} else {
			if($rowUser['role_id'] === '1') {
				echo '<select class="form-control" id="role_id" name="role_id">
				<option selected value="1">Administrator</option>
				<option value="2">Operator</option>
			</select>';
			} elseif ($rowUser['role_id'] === '2') {
				echo '<select class="form-control" id="role_id" name="role_id">
				<option value="1">Administrator</option>
				<option selected value="2">Operator</option>
			</select>';
			}
			}
			
			?>
		</div>		
		<div class="form-group">
			<label for="first_name">First Name</label>
			<input type="text" class="form-control" id="first_name" name="first_name" placeholder="" value="<?php print($rowUser['first_name']); ?>" maxlength="255" autocomplete="off" />
		</div>
		<div class="form-group">
			<label for="last_name">Last Name</label>
			<input type="text" class="form-control" id="last_name" name="last_name" placeholder="" value="<?php print($rowUser['last_name']); ?>" maxlength="14" autocomplete="off" />
		</div>
		<div class="form-group">
			<label for="email">Email</label>
			<input type="text" class="form-control" id="email" name="email" placeholder="" value="<?php print($rowUser['email']); ?>" autocomplete="off" />
		</div>
		<div class="form-group">
			<label for="username">Username</label>
			<input type="text" class="form-control" id="username" name="username" placeholder="" value="<?php print($rowUser['username']); ?>" autocomplete="off" />
		</div>
		<hr style="background-color: #a40000;">
		<div class="form-group">
			<label for="password">New Password</label>
			<input type="password" class="form-control" id="password" name="password" placeholder="" autocomplete="off" />
		</div>
		<div class="form-group">
			<label for="confirm_pwd">Confirm Password</label>
			<input type="password" class="form-control" id="confirm_pwd" name="confirm_pwd" placeholder="" autocomplete="off" />
		</div>								
			<input type="submit" name="btn_save" class="btn btn-success" value="Save">
			<input type="submit" name="btn_cancel" class="btn btn-danger" value="Cancel">							
	</form>

and here is the API that tells it what to do (PHP).

// Update User Info
if(isset($_POST['btn_save'])) {
	if ($_POST['password'] != $_POST['confirm_pwd']) {
    	die ('The two password provided do not match.');
	}
  
  $role_id = $_POST["role_id"];
  $first_name = $_POST["first_name"];
  $last_name = $_POST["last_name"];
  $email = $_POST["email"];
  $username = $_POST["username"];
  $password = password_hash($_POST['password'], PASSWORD_DEFAULT);
  $status = $_POST["status"];
  $id = $_POST["id"];  
  $stmt->execute();
  header('Location: ../../users.php');
}

The problem is when the user makes a change in the form and clicks the save button without entering anything in the new password and confirm password fields, the password changes to nothing and accepts blank values. So when the user logs out and logs back in, they get a login error that the username and password is incorrect (because the password was erased) I know I can make the field required, but that’s not what I want to do.

I basically want to say if the new password and confirm password fields are blank, then do not input any values (basically, don’t do anything), but if the user specifies a password in these two fields (and if they match), then change the password in the database. I’m not sure what the best way to write that is. I feel like it is something so simple, but I can’t figure out what it is.

What am I doing wrong?

Not trusting yourself.

Translate this line into code.

Translate this line into code.

Translate this line into code.

Translate this line into code.

3 Likes

I can think of some ways to do it:

  1. Run one query that updates all the information except the password. If the password has been entered, and both passwords match, run a second separate query to update the password for the user.

  2. Check whether the password has been entered and both passwords match, if so run one query that includes the password to be updated, and if not, run a different query that excludes that column.

  3. I was about to suggest using COALESCE in the query to only update the field if it is not null, but that won’t work because you’re inserting a password_hash() of your password, so it will never be null.

but it would be a fixed value…

There’s no reason it must always be a password_hash() value. The program logic can supply a null value if you are not updating the password field, or supply the password_hash() of the new password if you are updating the password field.

1 Like

True, that might still be less complex than two queries, or a choice of two queries.

Just as I thought, it was a simple fix…

I ran this if statement:

if(!empty($_POST['password'])) {
     // original SQL query here
} else {
     // updated SQL query here

That seemed to do the trick.

The password update should really be a process of it’s own separate from any other operation, meaning that should be the only thing you are doing.

1 Like