Project Overview

A User Profile Management System allows users to create and manage their profiles, including personal information, profile pictures, and preferences. This project covers user authentication, profile editing, file uploads for profile pictures, and secure data handling using PHP and MySQL.

Prerequisites

Ensure you have the following:

  • Web Server: Apache (using XAMPP, WAMP, or MAMP)
  • PHP: Version 7.4 or higher
  • MySQL: For database management
  • Code Editor: VS Code, Sublime Text, PHPStorm, etc.
  • Composer: For dependency management (optional)
  • Basic Understanding of User Authentication and File Uploads

Step-by-Step Procedure

1. Setting Up the Development Environment

  1. Install XAMPP:
    • Download from XAMPP Official Website.
    • Follow the installation wizard and install it in the default directory.
  2. Start Apache and MySQL:
    • Open the XAMPP Control Panel.
    • Start the Apache and MySQL modules.

2. Creating the Database

  1. Access phpMyAdmin:
    • Navigate to http://localhost/phpmyadmin/ in your browser.
  2. Create a New Database:
    • Click on “New” in the left sidebar.
    • Name the database user_profiles.
    • Choose “utf8mb4_unicode_ci” as the collation.
    • Click “Create”.
  3. Create a users Table:
    • Select the user_profiles database.
    • Click on “New” to create a table.
    • Define the table with the following fields:
    Field Type Null Key Default Extra id INT NO PRI NULL AUTO_INCREMENT username VARCHAR(50) NO UNI NULL email VARCHAR(100) NO UNI NULL password VARCHAR(255) NO NULL profile_pic VARCHAR(255) YES NULL bio TEXT YES NULL created_at TIMESTAMP NO CURRENT_TIMESTAMP
    • Click “Save”.

3. Project Structure

Organize your project files as follows:

user-profile-management/
├── uploads/           # Directory to store profile pictures
├── assets/
│   ├── css/
│   │   └── styles.css
│   └── js/
│       └── scripts.js
├── config/
│   └── db.php
├── templates/
│   ├── header.php
│   └── footer.php
├── register.php
├── login.php
├── profile.php
├── edit_profile.php
├── logout.php
└── README.md

Note: Ensure that the uploads/ directory is writable by the web server.

4. Configuration

a. Database Connection (config/db.php)

Create a file named db.php inside the config directory to handle database connections.

<?php
// config/db.php

$host = 'localhost';
$db   = 'user_profiles';
$user = 'root'; // Default XAMPP MySQL user
$pass = '';     // Default XAMPP MySQL password is empty
$charset = 'utf8mb4';

$dsn = "mysql:host=$host;dbname=$db;charset=$charset";

$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // Enable exceptions
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,       // Fetch associative arrays
    PDO::ATTR_EMULATE_PREPARES   => false,                  // Disable emulation
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
    // Handle connection errors
    http_response_code(500);
    echo "Database connection failed.";
    exit;
}
?>

5. Creating Reusable Templates

a. Header (templates/header.php)
<?php
// templates/header.php
session_start();
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>User Profile Management</title>
    <link rel="stylesheet" href="/user-profile-management/assets/css/styles.css">
</head>
<body>
    <header>
        <h1>User Profile Management</h1>
        <nav>
            <?php if (isset($_SESSION['user_id'])): ?>
                <a href="/user-profile-management/profile.php">My Profile</a>
                <a href="/user-profile-management/edit_profile.php">Edit Profile</a>
                <a href="/user-profile-management/logout.php">Logout</a>
            <?php else: ?>
                <a href="/user-profile-management/login.php">Login</a>
                <a href="/user-profile-management/register.php">Register</a>
            <?php endif; ?>
        </nav>
    </header>
    <main>
b. Footer (templates/footer.php)
<?php
// templates/footer.php
?>
    </main>
    <footer>
        <p>&copy; <?php echo date("Y"); ?> Your Company Name</p>
    </footer>
    <script src="/user-profile-management/assets/js/scripts.js"></script>
</body>
</html>

6. Styling the Application (assets/css/styles.css)

Add basic styles to enhance the appearance.

/* assets/css/styles.css */

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}

header, footer {
    background-color: #0066cc;
    color: #fff;
    padding: 10px 20px;
}

header h1, footer p {
    margin: 0;
}

nav a {
    color: #fff;
    margin-right: 15px;
    text-decoration: none;
}

main {
    padding: 20px;
}

form {
    max-width: 500px;
    margin: auto;
}

.form-group {
    margin-bottom: 15px;
}

label {
    display: block;
    margin-bottom: 5px;
}

input[type="text"],
input[type="email"],
input[type="password"],
textarea {
    width: 100%;
    padding: 8px;
    box-sizing: border-box;
}

button {
    padding: 10px 15px;
    background-color: #28a745;
    color: #fff;
    border: none;
    cursor: pointer;
}

button:hover {
    background-color: #218838;
}

.error {
    background-color: #f8d7da;
    color: #842029;
    padding: 15px;
    margin-bottom: 20px;
    border: 1px solid #f5c2c7;
    border-radius: 4px;
}

.success {
    background-color: #d1e7dd;
    color: #0f5132;
    padding: 15px;
    margin-bottom: 20px;
    border: 1px solid #badbcc;
    border-radius: 4px;
}

.profile-pic {
    max-width: 150px;
    border-radius: 50%;
}

7. User Registration (register.php)

This page allows new users to create an account.

<?php
// register.php

require 'config/db.php';
require 'templates/header.php';

$errors = [];
$success = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Sanitize and validate inputs
    $username = trim($_POST['username']);
    $email    = trim($_POST['email']);
    $password = trim($_POST['password']);
    $confirm_password = trim($_POST['confirm_password']);

    if (empty($username)) {
        $errors[] = 'Username is required.';
    }

    if (empty($email)) {
        $errors[] = 'Email is required.';
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errors[] = 'Invalid email format.';
    }

    if (empty($password)) {
        $errors[] = 'Password is required.';
    } elseif (strlen($password) < 6) {
        $errors[] = 'Password must be at least 6 characters.';
    }

    if ($password !== $confirm_password) {
        $errors[] = 'Passwords do not match.';
    }

    // Check if username or email already exists
    if (empty($errors)) {
        $stmt = $pdo->prepare('SELECT id FROM users WHERE username = ? OR email = ?');
        $stmt->execute([$username, $email]);
        if ($stmt->fetch()) {
            $errors[] = 'Username or email already exists.';
        }
    }

    if (empty($errors)) {
        // Hash the password
        $hashed_password = password_hash($password, PASSWORD_DEFAULT);

        // Insert into database
        $stmt = $pdo->prepare('INSERT INTO users (username, email, password) VALUES (?, ?, ?)');
        if ($stmt->execute([$username, $email, $hashed_password])) {
            $success = 'Registration successful. You can now <a href="login.php">login</a>.';
            // Clear form fields
            $username = $email = $password = $confirm_password = '';
        } else {
            $errors[] = 'There was an error registering. Please try again.';
        }
    }
}
?>

<h2>Register</h2>

<?php if (!empty($errors)): ?>
    <div class="error">
        <ul>
            <?php foreach($errors as $error): ?>
                <li><?php echo htmlspecialchars($error); ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

<?php if ($success): ?>
    <div class="success">
        <p><?php echo $success; ?></p>
    </div>
<?php endif; ?>

<form action="register.php" method="POST">
    <div class="form-group">
        <label for="username">Username:</label>
        <input type="text" id="username" name="username" value="<?php echo htmlspecialchars($username ?? ''); ?>" required>
    </div>

    <div class="form-group">
        <label for="email">Email:</label>
        <input type="email" id="email" name="email" value="<?php echo htmlspecialchars($email ?? ''); ?>" required>
    </div>

    <div class="form-group">
        <label for="password">Password (min 6 characters):</label>
        <input type="password" id="password" name="password" required>
    </div>

    <div class="form-group">
        <label for="confirm_password">Confirm Password:</label>
        <input type="password" id="confirm_password" name="confirm_password" required>
    </div>

    <button type="submit">Register</button>
</form>

<?php
require 'templates/footer.php';
?>

8. User Login (login.php)

This page allows existing users to log in.

<?php
// login.php

require 'config/db.php';
require 'templates/header.php';

$errors = [];
$success = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Sanitize and validate inputs
    $username = trim($_POST['username']);
    $password = trim($_POST['password']);

    if (empty($username)) {
        $errors[] = 'Username is required.';
    }

    if (empty($password)) {
        $errors[] = 'Password is required.';
    }

    if (empty($errors)) {
        // Fetch user from database
        $stmt = $pdo->prepare('SELECT id, password FROM users WHERE username = ?');
        $stmt->execute([$username]);
        $user = $stmt->fetch();

        if ($user && password_verify($password, $user['password'])) {
            // Password is correct, start a session
            $_SESSION['user_id'] = $user['id'];
            $_SESSION['username'] = $username;
            // Redirect to profile page
            header('Location: profile.php');
            exit;
        } else {
            $errors[] = 'Invalid username or password.';
        }
    }
}
?>

<h2>Login</h2>

<?php if (!empty($errors)): ?>
    <div class="error">
        <ul>
            <?php foreach($errors as $error): ?>
                <li><?php echo htmlspecialchars($error); ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

<?php if ($success): ?>
    <div class="success">
        <p><?php echo htmlspecialchars($success); ?></p>
    </div>
<?php endif; ?>

<form action="login.php" method="POST">
    <div class="form-group">
        <label for="username">Username:</label>
        <input type="text" id="username" name="username" value="<?php echo htmlspecialchars($username ?? ''); ?>" required>
    </div>

    <div class="form-group">
        <label for="password">Password:</label>
        <input type="password" id="password" name="password" required>
    </div>

    <button type="submit">Login</button>
</form>

<?php
require 'templates/footer.php';
?>

9. User Profile Page (profile.php)

This is a protected page where users can view their profile information.

<?php
// profile.php

require 'config/db.php';
require 'templates/header.php';

// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
    header('Location: login.php');
    exit;
}

// Fetch user information
$stmt = $pdo->prepare('SELECT username, email, profile_pic, bio, created_at FROM users WHERE id = ?');
$stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch();

if (!$user) {
    echo "<p>User not found.</p>";
    require 'templates/footer.php';
    exit;
}
?>

<h2>My Profile</h2>

<?php if ($user['profile_pic']): ?>
    <img src="uploads/<?php echo htmlspecialchars($user['profile_pic']); ?>" alt="Profile Picture" class="profile-pic">
<?php else: ?>
    <img src="uploads/default.png" alt="Default Profile Picture" class="profile-pic">
<?php endif; ?>

<p><strong>Username:</strong> <?php echo htmlspecialchars($user['username']); ?></p>
<p><strong>Email:</strong> <?php echo htmlspecialchars($user['email']); ?></p>
<p><strong>Bio:</strong> <?php echo nl2br(htmlspecialchars($user['bio'] ?? '')); ?></p>
<p><strong>Member Since:</strong> <?php echo htmlspecialchars($user['created_at']); ?></p>

<a href="edit_profile.php">Edit Profile</a>

<?php
require 'templates/footer.php';
?>

10. Editing User Profile (edit_profile.php)

This page allows users to update their profile information, including uploading a new profile picture.

<?php
// edit_profile.php

require 'config/db.php';
require 'templates/header.php';

// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
    header('Location: login.php');
    exit;
}

// Fetch existing user information
$stmt = $pdo->prepare('SELECT username, email, profile_pic, bio FROM users WHERE id = ?');
$stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch();

if (!$user) {
    echo "<p>User not found.</p>";
    require 'templates/footer.php';
    exit;
}

$errors = [];
$success = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Sanitize and validate inputs
    $username = trim($_POST['username']);
    $email    = trim($_POST['email']);
    $bio      = trim($_POST['bio']);

    if (empty($username)) {
        $errors[] = 'Username is required.';
    }

    if (empty($email)) {
        $errors[] = 'Email is required.';
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errors[] = 'Invalid email format.';
    }

    // Handle profile picture upload if a new file is uploaded
    if (isset($_FILES['profile_pic']) && $_FILES['profile_pic']['error'] !== UPLOAD_ERR_NO_FILE) {
        if ($_FILES['profile_pic']['error'] === UPLOAD_ERR_OK) {
            $fileTmpPath = $_FILES['profile_pic']['tmp_name'];
            $originalName = $_FILES['profile_pic']['name'];
            $fileSize = $_FILES['profile_pic']['size'];
            $fileType = $_FILES['profile_pic']['type'];
            $fileNameCmps = explode(".", $originalName);
            $fileExtension = strtolower(end($fileNameCmps));

            // Sanitize file name
            $newFileName = md5(time() . $originalName) . '.' . $fileExtension;

            // Allowed file extensions
            $allowedfileExtensions = ['jpg', 'gif', 'png'];

            if (in_array($fileExtension, $allowedfileExtensions)) {
                // Directory in which the uploaded file will be moved
                $uploadFileDir = './uploads/';
                $dest_path = $uploadFileDir . $newFileName;

                if(move_uploaded_file($fileTmpPath, $dest_path)) 
                {
                    // Delete old profile picture if exists and not default
                    if ($user['profile_pic'] && $user['profile_pic'] !== 'default.png') {
                        unlink($uploadFileDir . $user['profile_pic']);
                    }
                }
                else 
                {
                    $errors[] = 'There was an error moving the uploaded file.';
                }
            }
            else
            {
                $errors[] = 'Upload failed. Allowed file types: ' . implode(',', $allowedfileExtensions);
            }
        }
        else
        {
            $errors[] = 'There is some error in the file upload. Please check the following error.<br>';
            $errors[] = 'Error:' . $_FILES['profile_pic']['error'];
        }
    }

    // Check if username or email already exists (excluding current user)
    if (empty($errors)) {
        $stmt = $pdo->prepare('SELECT id FROM users WHERE (username = ? OR email = ?) AND id != ?');
        $stmt->execute([$username, $email, $_SESSION['user_id']]);
        if ($stmt->fetch()) {
            $errors[] = 'Username or email already exists.';
        }
    }

    if (empty($errors)) {
        // Update in database
        if (isset($newFileName)) {
            $stmt = $pdo->prepare('UPDATE users SET username = ?, email = ?, bio = ?, profile_pic = ? WHERE id = ?');
            $result = $stmt->execute([$username, $email, $bio, $newFileName, $_SESSION['user_id']]);
        } else {
            $stmt = $pdo->prepare('UPDATE users SET username = ?, email = ?, bio = ? WHERE id = ?');
            $result = $stmt->execute([$username, $email, $bio, $_SESSION['user_id']]);
        }

        if ($result) {
            $success = 'Profile updated successfully.';
            // Refresh user data
            $stmt = $pdo->prepare('SELECT username, email, profile_pic, bio FROM users WHERE id = ?');
            $stmt->execute([$_SESSION['user_id']]);
            $user = $stmt->fetch();
        } else {
            $errors[] = 'There was an error updating your profile. Please try again.';
        }
    }
}
?>

<h2>Edit Profile</h2>

<?php if (!empty($errors)): ?>
    <div class="error">
        <ul>
            <?php foreach($errors as $error): ?>
                <li><?php echo htmlspecialchars($error); ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

<?php if ($success): ?>
    <div class="success">
        <p><?php echo htmlspecialchars($success); ?></p>
    </div>
<?php endif; ?>

<form action="edit_profile.php" method="POST" enctype="multipart/form-data">
    <div class="form-group">
        <label for="username">Username:</label>
        <input type="text" id="username" name="username" value="<?php echo htmlspecialchars($user['username']); ?>" required>
    </div>

    <div class="form-group">
        <label for="email">Email:</label>
        <input type="email" id="email" name="email" value="<?php echo htmlspecialchars($user['email']); ?>" required>
    </div>

    <div class="form-group">
        <label for="bio">Bio:</label>
        <textarea id="bio" name="bio" rows="5"><?php echo htmlspecialchars($user['bio'] ?? ''); ?></textarea>
    </div>

    <div class="form-group">
        <label for="profile_pic">Profile Picture:</label>
        <input type="file" id="profile_pic" name="profile_pic" accept="image/*">
    </div>

    <button type="submit">Update Profile</button>
</form>

<?php
require 'templates/footer.php';
?>

11. User Logout (logout.php)

This script logs the user out by destroying the session.

<?php
// logout.php

session_start();
session_unset();
session_destroy();

// Redirect to login page
header('Location: login.php');
exit;
?>

12. Testing the Application

  1. Access the Registration Page:
    • Navigate to http://localhost/user-profile-management/register.php.
    • Fill in the registration form and submit.
    • Verify that the user is registered and redirected appropriately.
  2. Access the Login Page:
    • Navigate to http://localhost/user-profile-management/login.php.
    • Enter the registered credentials and log in.
    • Verify access to the profile page.
  3. Edit Profile:
    • Navigate to http://localhost/user-profile-management/edit_profile.php.
    • Update profile information and upload a new profile picture.
    • Verify that changes are reflected on the profile page.
  4. Logout:
    • Click on “Logout”.
    • Verify that the session is destroyed and access to protected pages is restricted.

13. Deployment Considerations

When deploying to a live server, consider the following:

  • Secure File Uploads:
    • Restrict file types and sizes to prevent malicious uploads.
    • Store uploaded files outside the web root or restrict direct access using .htaccess.
  • Implement HTTPS:
    • Ensure your website uses HTTPS to encrypt data transmission.
  • Protect Sensitive Data:
    • Use environment variables or secure configuration methods for database credentials.
  • Session Security:
    • Implement secure session handling practices, such as regenerating session IDs upon login.
  • Input Validation:
    • Thoroughly validate and sanitize all user inputs to prevent SQL injection and XSS attacks.
  • Error Reporting:
    • Disable detailed error messages in production to prevent information leakage.
    // In production, set error reporting to minimal ini_set('display_errors', 0); ini_set('log_errors', 1);
  • Regular Backups:
    • Implement regular backups of your database and uploaded files.
Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *