prepare(" SELECT user_pass FROM user WHERE user_id = ? LIMIT 1 "); if (!$stmt) { $password_error = 'Unable to check your account.'; } else { $stmt->bind_param("i", $LoginMemberID); $stmt->execute(); $result = $stmt->get_result(); $current_user = $result->fetch_assoc(); $stmt->close(); if (!$current_user) { $password_error = 'Unable to find your user account.'; } else { $current_password_hash = $current_user['user_pass'] ?? ''; } } } /* |-------------------------------------------------------------------------- | DO NOT ALLOW CURRENT PASSWORD |-------------------------------------------------------------------------- */ if ( $password_error === '' && !empty($current_password_hash) && password_verify( $new_password, $current_password_hash ) ) { $password_error = 'You cannot reuse your current password. Please choose a different password.'; } /* |-------------------------------------------------------------------------- | GET PASSWORD HISTORY |-------------------------------------------------------------------------- */ $password_history = []; if ($password_error === '') { $stmt = $mysqli->prepare(" SELECT data_id, data_value, data_date, password_slot FROM user_data WHERE data_user_id = ? AND data_type = 'new-password' ORDER BY data_date DESC, data_id DESC "); if (!$stmt) { $password_error = 'Unable to check your password history.'; } else { $stmt->bind_param( "i", $LoginMemberID ); $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { $password_history[] = $row; } $stmt->close(); } } /* |-------------------------------------------------------------------------- | PURGE ANY PASSWORDS OLDER THAN THE NEWEST 6 |-------------------------------------------------------------------------- */ if ( $password_error === '' && count($password_history) > 6 ) { $records_to_delete = array_slice($password_history, 6); $delete_stmt = $mysqli->prepare(" UPDATE user_data SET data_type = 'old-password-purged', password_slot = NULL WHERE data_id = ? AND data_user_id = ? AND data_type = 'new-password' "); if ($delete_stmt) { foreach ($records_to_delete as $record) { $delete_id = (int)$record['data_id']; $delete_stmt->bind_param( "ii", $delete_id, $LoginMemberID ); $delete_stmt->execute(); } $delete_stmt->close(); } $password_history = array_slice($password_history, 0, 6); } /* |-------------------------------------------------------------------------- | ASSIGN PASSWORD SLOTS TO EXISTING RECORDS |-------------------------------------------------------------------------- */ if ($password_error === '') { $used_slots = []; foreach ($password_history as &$history_record) { $slot = (int)($history_record['password_slot'] ?? 0); if ($slot >= 1 && $slot <= 6 && !in_array($slot, $used_slots, true)) { $used_slots[] = $slot; continue; } $new_slot = 1; while (in_array($new_slot, $used_slots, true) && $new_slot <= 6) { $new_slot++; } if ($new_slot > 6) { $new_slot = 6; } $data_id = (int)$history_record['data_id']; $slot_stmt = $mysqli->prepare(" UPDATE user_data SET password_slot = ? WHERE data_id = ? AND data_user_id = ? AND data_type = 'new-password' "); if ($slot_stmt) { $slot_stmt->bind_param( "iii", $new_slot, $data_id, $LoginMemberID ); $slot_stmt->execute(); $slot_stmt->close(); $history_record['password_slot'] = $new_slot; $used_slots[] = $new_slot; } } unset($history_record); } /* |-------------------------------------------------------------------------- | CHECK AGAINST PREVIOUS 6 PASSWORDS |-------------------------------------------------------------------------- */ if ($password_error === '') { foreach ($password_history as $old_password) { $old_hash = $old_password['data_value'] ?? ''; if ( !empty($old_hash) && password_verify( $new_password, $old_hash ) ) { $password_error = 'You cannot reuse any of your last 6 passwords. Please choose a different password.'; break; } } } /* |-------------------------------------------------------------------------- | SAVE NEW PASSWORD |-------------------------------------------------------------------------- */ if ($password_error === '') { $new_hash = password_hash( $new_password, PASSWORD_DEFAULT ); $mysqli->begin_transaction(); try { /* |-------------------------------------------------------------------------- | UPDATE CURRENT PASSWORD |-------------------------------------------------------------------------- */ $stmt = $mysqli->prepare(" UPDATE user SET user_updated_date = NOW(), user_pass = ? WHERE user_id = ? "); if (!$stmt) { throw new Exception( 'Unable to prepare password update.' ); } $stmt->bind_param( "si", $new_hash, $LoginMemberID ); if (!$stmt->execute()) { throw new Exception( 'Unable to update password.' ); } $stmt->close(); /* |-------------------------------------------------------------------------- | GET CURRENT PASSWORD HISTORY AGAIN |-------------------------------------------------------------------------- */ $stmt = $mysqli->prepare(" SELECT data_id, password_slot, data_date FROM user_data WHERE data_user_id = ? AND data_type = 'new-password' ORDER BY data_date ASC, data_id ASC "); if (!$stmt) { throw new Exception( 'Unable to prepare password history.' ); } $stmt->bind_param( "i", $LoginMemberID ); $stmt->execute(); $result = $stmt->get_result(); $password_records = []; while ($row = $result->fetch_assoc()) { $password_records[] = $row; } $stmt->close(); /* |-------------------------------------------------------------------------- | FEWER THAN 6 PASSWORD HISTORY RECORDS |-------------------------------------------------------------------------- */ if (count($password_records) < 6) { $used_slots = []; foreach ($password_records as $record) { $record_slot = (int)($record['password_slot'] ?? 0); if ( $record_slot >= 1 && $record_slot <= 6 ) { $used_slots[] = $record_slot; } } $new_slot = 1; while ( in_array( $new_slot, $used_slots, true ) && $new_slot <= 6 ) { $new_slot++; } if ($new_slot > 6) { $new_slot = 6; } $stmt = $mysqli->prepare(" INSERT INTO user_data ( data_type, data_value, data_user_id, data_date, password_slot ) VALUES ( 'new-password', ?, ?, NOW(), ? ) "); if (!$stmt) { throw new Exception( 'Unable to create password history.' ); } $stmt->bind_param( "sii", $new_hash, $LoginMemberID, $new_slot ); if (!$stmt->execute()) { throw new Exception( 'Unable to save password history.' ); } $stmt->close(); } else { /* |-------------------------------------------------------------------------- | ALREADY HAVE 6 - REUSE OLDEST SLOT |-------------------------------------------------------------------------- */ $oldest_record = $password_records[0]; $oldest_id = (int)$oldest_record['data_id']; $oldest_slot = (int)($oldest_record['password_slot'] ?? 0); if ( $oldest_slot < 1 || $oldest_slot > 6 ) { $oldest_slot = 1; } $stmt = $mysqli->prepare(" UPDATE user_data SET data_value = ?, data_date = NOW(), password_slot = ? WHERE data_id = ? AND data_user_id = ? AND data_type = 'new-password' "); if (!$stmt) { throw new Exception( 'Unable to update password history.' ); } $stmt->bind_param( "siii", $new_hash, $oldest_slot, $oldest_id, $LoginMemberID ); if (!$stmt->execute()) { throw new Exception( 'Unable to update password history.' ); } $stmt->close(); } /* |-------------------------------------------------------------------------- | REMOVE ADMIN PASSWORD RESET REQUIREMENT |-------------------------------------------------------------------------- */ $stmt = $mysqli->prepare(" UPDATE user_data SET data_type = 'password-reset-completed', data_date = NOW() WHERE data_user_id = ? AND data_type = 'password-reset-required' "); if (!$stmt) { throw new Exception( 'Unable to clear password reset requirement.' ); } $stmt->bind_param( "i", $LoginMemberID ); if (!$stmt->execute()) { throw new Exception( 'Unable to clear password reset requirement.' ); } $stmt->close(); /* |-------------------------------------------------------------------------- | COMMIT |-------------------------------------------------------------------------- */ $mysqli->commit(); $password_success = true; $_SESSION['change_password_csrf'] = bin2hex(random_bytes(32)); $csrf_token = $_SESSION['change_password_csrf']; } catch (Throwable $e) { $mysqli->rollback(); error_log('ChangePW error: ' . $e->getMessage()); $password_error = 'Your password could not be changed. Please try again.'; } } } ?> <?php echo htmlspecialchars( $title, ENT_QUOTES, 'UTF-8' ); ?>

Change password

Password changed successfully

, your password has been changed.

You will be returned to the home page.

Password change required

Your password has been reset by an administrator. The password you just used was temporary.

Please choose your own new password before continuing to the intranet.

, you're about to change your password. Please enter your new password below.

Password not changed.

Password must contain:

A lowercase letter

A capital (uppercase) letter

A number

Minimum 8 characters

Matching passwords

You cannot reuse any of your last 6 passwords.