The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
For a logged-in user’s private profile, read their ID from the PHP session, fetch the matching row with a PDO prepared statement, then escape each value before printing it in HTML:
session user ID → prepared SELECT → fetch one row → escape output
This example assumes PHP, MySQL, PDO, and a users table. A public profile selected by URL ID is a different case: validate the ID and return only fields intended to be public.
1. Create a users table
A profile page should retrieve only the fields it needs. Keep authentication secrets, such as password hashes, out of the profile query and page.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
display_name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
bio TEXT NULL,
profile_image VARCHAR(255) NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
The 255-character hash column allows room for password hashes as the default algorithm changes over time; PHP recommends sufficient space for this purpose (PHP password_hash()). Never select or display password_hash on a profile page.
#1 Best Overall
2. Set up PDO in a reusable file
For example, put this in db.php and include it where the application needs a database connection. Keep production credentials out of publicly served source files where practical, and give the database account only the privileges the application requires.
<?php
// db.php
declare(strict_types=1);
$dsn = 'mysql:host=localhost;dbname=example;charset=utf8mb4';
$dbUser = 'app_user';
$dbPassword = 'database_password';
$pdo = new PDO($dsn, $dbUser, $dbPassword, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
The character set belongs in the DSN. Exception mode makes database failures easier to handle consistently, while associative fetch mode returns rows keyed by column name. PDO provides a common database interface, but security depends on how the application uses it (PDO overview).
Rank #2
3. Save only the user ID at login
After checking a submitted password against the stored hash, save the authenticated user’s ID in the session—not the entire database row, and never the password.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
<?php
session_start();
$stmt = $pdo->prepare(
'SELECT id, password_hash
FROM users
WHERE email = :email
LIMIT 1'
);
$stmt->execute(['email' => $email]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password_hash'])) {
session_regenerate_id(true);
$_SESSION['user_id'] = (int) $user['id'];
header('Location: profile.php');
exit;
}
Regenerating the session ID after successful authentication is a common defense against session fixation; see PHP’s session_regenerate_id() guidance. The PHP session-security manual notes that immediately deleting the old session can cause problems with concurrent requests or unstable connections, so production session handling should account for the application’s request patterns (session security management).
4. Fetch and display the logged-in user
Here is the complete core of profile.php. Call session_start() before reading the session and before sending page output. The ID check accepts an integer or digit-only string and rejects malformed session state before casting.
<?php
// profile.php
declare(strict_types=1);
session_start();
if (
!isset($_SESSION['user_id']) ||
(!is_int($_SESSION['user_id']) && !ctype_digit((string) $_SESSION['user_id']))
) {
header('Location: login.php');
exit;
}
$userId = (int) $_SESSION['user_id'];
require __DIR__ . '/db.php';
$stmt = $pdo->prepare(
'SELECT id, username, display_name, email, bio, profile_image
FROM users
WHERE id = :id
LIMIT 1'
);
$stmt->execute(['id' => $userId]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user === false) {
http_response_code(404);
exit('User profile not found.');
}
function e(?string $value): string
{
return htmlspecialchars(
$value ?? '',
ENT_QUOTES | ENT_SUBSTITUTE,
'UTF-8'
);
}
?>
<h1><?= e($user['display_name']) ?></h1>
<p>Username: <?= e($user['username']) ?></p>
<p>Email: <?= e($user['email']) ?></p>
<p><?= nl2br(e($user['bio'])) ?></p>
<?php if (!empty($user['profile_image'])): ?>
<img src="<?= e($user['profile_image']) ?>"
alt="<?= e($user['display_name']) ?>'s profile image">
<?php endif; ?>
session_start() resumes or creates the session for the request (PHP session_start()). The three PDO steps are prepare(), execute(), and fetch(): prepare the SQL, supply the ID as a value, then read the one matching row. PHP documents that parameter markers represent values, not table names or column names (PDO::prepare(); PDOStatement::execute()).
Rank #4
With PDO::FETCH_ASSOC, the row is an array such as $user['display_name']. fetch() returns false when there is no row available, so the missing-user branch is important (PDOStatement::fetch()).
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstall5. Keep SQL protection and HTML escaping separate
A prepared statement helps protect the SQL query when values are bound correctly. It does not make returned text safe to insert into HTML. Escape values when rendering them with htmlspecialchars(), as the e() helper does above. This matters especially for editable fields such as names and biographies.
Likewise, HTML escaping is not a universal sanitizer. An image URL or website URL needs appropriate scheme and format validation as well as attribute escaping; escaping alone does not make a javascript: URL safe. Prepared statements also cannot bind arbitrary table or column names. If identifiers must vary, choose them from a strict server-side allowlist rather than accepting them from the request. See PHP’s SQL injection guidance and filter_input() documentation.
6. Public profiles use a different ID source
A URL such as /profile.php?id=42 can be appropriate for a public profile. Validate the supplied ID, use it as a prepared-statement value, and select only fields that are meant to be public:
<?php
$id = filter_input(
INPUT_GET,
'id',
FILTER_VALIDATE_INT,
['options' => ['min_range' => 1]]
);
if ($id === false || $id === null) {
http_response_code(400);
exit('Invalid user ID.');
}
$stmt = $pdo->prepare(
'SELECT id, username, display_name, bio, profile_image
FROM users
WHERE id = :id
LIMIT 1'
);
$stmt->execute(['id' => $id]);
$user = $stmt->fetch();
if ($user === false) {
http_response_code(404);
exit('Profile not found.');
}
filter_input() returns false for a failed validation and null when the input is absent. Its default filter does not validate input usefully; request explicit validation as shown (PHP filter_input()). A URL ID does not grant permission to view private account details. Authentication identifies the requester; authorization decides which records and fields that requester may access.
For an admin viewing another user, obtain the target ID through the appropriate route or form, then check the requester’s admin permission before returning administrative or private fields. For a lookup by username or email, use the same prepared-query pattern and make the identifying column unique if it is expected to match one user. Do not use a password as a profile lookup key; password verification belongs in the login flow.
7. Use fetch() for one profile, fetchAll() for a list
| Need | Approach |
|---|---|
| One user profile | $stmt->fetch(PDO::FETCH_ASSOC) |
| Multiple rows, such as a small user list | $stmt->fetchAll(PDO::FETCH_ASSOC) |
| Associative array result | PDO::FETCH_ASSOC |
| Object-style result | PDO::FETCH_OBJ |
fetch() reads the next row; fetchAll() reads all remaining rows. A profile query expects one record, so use fetch(). Loading all rows is unnecessary for a single profile and can consume more memory for large result sets (PDOStatement).
Quick Recap
8. Common errors and what to check
- Undefined array key
user_id: Start the session before reading it, verify the login code sets the same key, and redirect if no authenticated ID is present. Confirm that the browser sends the session cookie. PHP documents session values in $_SESSION. fetch()called onfalse: A query may have failed and left the statement variable false. Exception mode helps surface the database failure; inspect detailed errors in server-side logs, not in a public response.fetch()returns false: No row matched, or no row remains. Check that the session ID belongs to an existing account, the database and table are correct, and theWHEREcondition matches. Return an appropriate 404 or handle a deleted/disabled account according to your application’s policy.- Empty or missing template values: Compare selected column names with the actual schema and the keys used in the template. Check for nullable columns and use a fallback such as
$user['bio'] ?? ''. - Unknown column: Confirm the schema and query spelling. An explicit select list makes mismatches easier to spot than
SELECT *. - Malformed ID: Validate before casting. A cast by itself can silently turn malformed input into zero and conceal a bug.
- Named and positional placeholders mixed: Use one style per statement and provide a value for every marker. For example, use
:idwith['id' => $userId], or?with[$userId]. See execute().
Security checklist
- Use the session ID for the current user’s private profile, not a client-controlled URL ID.
- Use a prepared statement for values and select only the columns the page needs.
- Keep password hashes, reset tokens, internal notes, and other secrets out of profile results.
- Regenerate the session ID after successful login and keep session handling consistent.
- Check authorization separately when a user can request another person’s record.
- Escape rendered HTML text and attributes, and validate URL fields for their intended schemes.
- Use generic user-facing database errors; keep diagnostic details in protected logs.
- Keep credentials private and restrict the database account’s privileges.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

