πŸ“– 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.

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=2 loads UserController::show() and displays the user's profile.
Edit Mode
profile.php?edit&id=2 triggers UserController::edit() and loads the editable form view.
Update Mode
A POST submission from the form (with a hidden id) triggers UserController::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 id through 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

Last updated: August 8, 2025 at 1:26 PM