π PHP Updating User Profiles
π Project Structure
This layout illustrates how user input flows through your app β from form submission to controller logic and back to the view β with shared elements organized for reuse:
project-root/
βββ controllers/
β βββ UserController.php β logic for displaying and processing the form
βββ models/
β βββ UserModel.php β database interaction for user records
βββ views/
β βββ partials/
β β βββ header.php β shared HTML header and navigation
β β βββ footer.php β shared footer and closing tags
β βββ profile/
β βββ create.php β displays the registration form
β βββ edit.php β displays the edit profile form
β βββ show.php β displays the user profile view
β βββ partials/
β βββ form-fields.php β shared form fields for create and edit views
βββ index.php β default entry point for app
βββ profile.php β entry point for profile view/edit/update
βββ register.php β entry point for user registration
This structure promotes modular design by separating responsibilities β models for data access, controllers for logic, and views for output β making your application easier to scale and maintain.
Using MySQL Update
In a typical workflow, a user selects an existing record β such as their own profile β and is routed to an edit screen. This route is triggered by a link or button that passes the user's unique ID through the query string.
Adding an Edit Link
The following example adds an Edit button to the profile display view:
views/profile/show.php
<a class="btn btn-warning" href="profile.php?edit&id=<?= htmlspecialchars($user['id']) ?>">Edit Profile</a>
This link directs the user to profile.php in "edit" mode. The controller and view files handle the logic and layout separately for clarity and security.
β οΈ Important: This link only works if a valid user id exists in your database. If the id is missing or invalid, your controller should show an error or redirect to a safe fallback. Always validate incoming IDs before using them in a query.
Update Process
Profile updates are handled using a combination of query parameters, form POSTs, and controller logic. There is no formal router β instead, profile.php checks the request type and query string to decide what to do.
Request Handling Modes
- View Mode
profile.php?id=2loadsUserController::show()and displays the user's profile.- Edit Mode
profile.php?edit&id=2triggersUserController::edit()and loads the editable form view.- Update Mode
- A POST submission from the form (with a hidden
id) triggersUserController::update()to validate and save changes.
Routing Logic in profile.php
The following conditional block routes user requests to the correct controller method:
<?php
require_once 'controllers/UserController.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
UserController::update();
} elseif (isset($_GET['edit'])) {
UserController::edit();
} else {
UserController::show();
}
This pattern mimics a simple front controller and keeps profile.php clean and scalable.
Load Edit View
Add this method to your existing UserController class to support loading the edit view.
class UserController {
// ... other methods ...
public static function edit() {
$id = $_GET['id'] ?? null;
if ($id) {
$user = UserModel::getUserById($id);
if ($user) {
require 'views/profile/edit.php';
return;
}
}
header("Location: index.php?error=" . urlencode("We could not find you in the system."));
exit;
}
}
π‘ Tip: Your edit.php form must include a hidden id field so the controller knows which record to update: <input type="hidden" name="id" value="<?= htmlspecialchars($user['id']) ?>">
Building the Views
Now that the controller logic is in place to handle both viewing and editing a user profile, it's time to focus on the views. Our app uses two views that both display a form: create.php and edit.php. Although these forms serve different purposes β one for registering, one for updating β they share the same basic structure and input fields.
In line with the MVC pattern and the DRY principle ("Don't Repeat Yourself"), weβll extract the shared input elements into a reusable partial file. This keeps your views consistent and makes the code easier to maintain as your application grows.
Refactoring Views with Partials
Create a new file named views/profile/partials/form-fields.php and move just the input fields into it. This partial should contain no <form> tags or buttons β only the inputs and labels.
π Note: If it doesnβt already exist, youβll need to create a new partials folder inside your views/profile directory. This is where youβll save your new form-fields.php partial so that it can be reused across multiple views.
views/profile/partials/form-fields.php
<div>
<label for="name" class="form-label">Name:</label>
<input type="text" class="form-control" name="name" id="name"
value="<?= htmlspecialchars($user['name'] ?? $post['name'] ?? '') ?>">
<?php if (!empty($errors['name'])): ?>
<p class="text-danger"><?= $errors['name'] ?></p>
<?php endif; ?>
</div>
<div>
<label for="email" class="form-label">Email:</label>
<input type="email" class="form-control" name="email" id="email"
value="<?= htmlspecialchars($user['email'] ?? $post['email'] ?? '') ?>">
<?php if (!empty($errors['email'])): ?>
<p class="text-danger"><?= $errors['email'] ?></p>
<?php endif; ?>
</div>
Then include this partial in both your create.php and edit.php views:
create.php
<?php include 'views/partials/header.php'; ?>
<h2>Create Profile</h2>
<form method="post" action="register.php">
<?php include 'partials/form-fields.php'; ?>
<button class="btn btn-primary" type="submit">Create Account</button>
</form>
<?php include 'views/partials/footer.php'; ?>
edit.php
<?php include 'views/partials/header.php'; ?>
<h2>Edit Profile</h2>
<form method="post" action="profile.php">
<input type="hidden" name="id" value="<?= htmlspecialchars($user['id']) ?>">
<?php include 'partials/form-fields.php'; ?>
<button class="btn btn-primary" type="submit">Save Changes</button>
</form>
<?php include 'views/partials/footer.php'; ?>
π§ Best Practice: Use partials for repeatable UI elements like form fields. It keeps your views DRY (Don't Repeat Yourself) and easier to update as your form logic evolves.
Update User
class UserController {
// ... other methods ...
public static function update() {
$id = $_POST['id'] ?? null;
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
$errors = [];
if (!$name) $errors[] = "Name is required.";
if (!$email) $errors[] = "Email is required.";
if (empty($errors)) {
if (UserModel::updateUser($id, $name, $email)) {
header("Location: profile.php?success=" . urlencode("Profile updated successfully."));
exit;
} else {
$errors[] = "Failed to update user.";
}
}
$user = ['id' => $id, 'name' => $name, 'email' => $email];
require 'views/profile/edit.php';
}
}
Add this method to your UserModel class to update a user record securely using a parameterized SQL statement:
class UserModel {
public static function updateUser($id, $name, $email) {
$db = static::getDB();
$stmt = $db->prepare("UPDATE users SET name = :name, email = :email WHERE id = :id LIMIT 1");
return $stmt->execute([
':name' => $name,
':email' => $email,
':id' => $id
]);
}
}
π‘οΈ Security Tip: Always use bound parameters in your SQL queries to prevent injection attacks. Never insert raw input directly into query strings.
Displaying Success and Error Messages
After a user updates their profile, it's important to provide clear feedback confirming whether the update was successful or not. A simple way to do this is by passing a message in the URL query string and displaying it in your view.
1. Create an index.php Redirect Page
After an update, you can redirect the user to a basic page like index.php. This will serve as a visual landing page to show any status messages.
<?php include 'views/partials/header.php'; ?>
<h2>My Home Page</h2>
<?php include 'views/partials/footer.php'; ?>
2. Add Message Logic to header.php
Insert this snippet into the end of your header.php file (just after the opening <div class="container">), so it appears on all views:
<?php if (isset($_GET['success'])): ?>
<div class="alert alert-success" role="alert">
<?= htmlspecialchars($_GET['success']) ?>
</div>
<?php endif; ?>
<?php if (isset($_GET['error'])): ?>
<div class="alert alert-danger" role="alert">
<?= htmlspecialchars($_GET['error']) ?>
</div>
<?php endif; ?>
This will display styled Bootstrap alert boxes when the URL contains ?success=... or ?error=....
3. What is URL Encoding?
When you pass text in a URL, characters like spaces must be encoded. Use PHP's urlencode() function to safely prepare a string for the query string.
Error Message Example
header("Location: index.php?error=" . urlencode("We could not find you in the system."));
Success Message Example
header("Location: profile.php?success=" . urlencode("Profile updated successfully."));
This converts the message into a URL-safe format like: index.php?success=Profile+updated+successfully.. It will still appear human-readable after decoding in the browser.
π¬ Best Practice: Always encode messages passed via URL to avoid breaking the query or exposing unsafe characters.
Summary / Takeaways
- Use query strings to switch between view, edit, and update modes in
profile.php - Keep controller methods focused on one task each
- Pass a hidden
idthrough the form to support updates - Use parameterized queries in your model for safe updates
- Always validate user input before saving to the database
Additional Resources
- π PHP PDO: prepare()
- π MDN: POST Method
- π PHP Superglobals
Last updated: August 8, 2025 at 1:26 PM