39038-vm/profile.php
2026-03-14 13:13:28 +00:00

218 lines
8.7 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/layout.php'; require_login();
ensure_schema();
// Demo auth: if not logged in, pretend to be user 1
$userId = $_SESSION['user_id'] ?? 1;
$errors = [];
// Fetch current user data
try {
$stmt = db()->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute([':id' => $userId]);
$user = $stmt->fetch();
if (!$user) {
die("Demo user not found. Please register an account first.");
}
} catch (Throwable $e) {
die("Database error: " . $e->getMessage());
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'update_profile') {
$fullName = trim($_POST['full_name'] ?? '');
if ($fullName === '') {
$errors[] = t('error_required');
}
$profilePicPath = $user['profile_picture'];
// Handle file upload
if (isset($_FILES['profile_picture']) && $_FILES['profile_picture']['error'] === UPLOAD_ERR_OK) {
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
$fileInfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($fileInfo, $_FILES['profile_picture']['tmp_name']);
finfo_close($fileInfo);
if (!in_array($mimeType, $allowedTypes)) {
$errors[] = t('invalid_image');
} else {
$uploadDir = __DIR__ . '/uploads/profiles/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0775, true);
}
$extension = pathinfo($_FILES['profile_picture']['name'], PATHINFO_EXTENSION);
$filename = 'profile_' . $userId . '_' . time() . '.' . $extension;
$destination = $uploadDir . $filename;
if (move_uploaded_file($_FILES['profile_picture']['tmp_name'], $destination)) {
$profilePicPath = '/uploads/profiles/' . $filename;
} else {
$errors[] = t('upload_failed');
}
}
}
// Password Update Logic
$newPassword = trim($_POST['new_password'] ?? '');
$confirmPassword = trim($_POST['confirm_password'] ?? '');
if ($newPassword !== '') {
if ($newPassword !== $confirmPassword) {
$errors[] = t('passwords_do_not_match');
} elseif (strlen($newPassword) < 6) {
$errors[] = t('password_too_short');
}
}
if (!$errors) {
try {
$sql = "UPDATE users SET full_name = :name, profile_picture = :pic";
$params = [
':name' => $fullName,
':pic' => $profilePicPath,
':id' => $userId
];
if ($newPassword !== '') {
$sql .= ", password = :pass";
$params[':pass'] = password_hash($newPassword, PASSWORD_DEFAULT);
}
$sql .= " WHERE id = :id";
$updateStmt = db()->prepare($sql);
$updateStmt->execute($params);
$msg = t('profile_updated');
if ($newPassword !== '') {
$msg .= ' ' . t('password_updated');
}
set_flash('success', $msg);
header("Location: " . url_with_lang('profile.php'));
exit;
} catch (Throwable $e) {
$errors[] = "Database update failed: " . $e->getMessage();
}
}
}
render_header(t('my_profile'), 'profile');
$flash = get_flash();
?>
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6">
<div class="panel p-4 p-md-5">
<div class="d-flex align-items-center mb-4">
<i class="bi bi-person-badge fs-2 text-primary me-3"></i>
<h2 class="section-title mb-0"><?= e(t('my_profile')) ?></h2>
</div>
<?php if ($flash): ?>
<div class="alert alert-<?= $flash['type'] === 'error' ? 'danger' : 'success' ?> mb-4" data-auto-dismiss="true">
<?= e($flash['message']) ?>
</div>
<?php endif; ?>
<?php if ($errors): ?>
<div class="alert alert-danger mb-4">
<ul class="mb-0">
<?php foreach ($errors as $err): ?>
<li><?= e($err) ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<form method="post" enctype="multipart/form-data"> <?= csrf_field() ?>
<input type="hidden" name="action" value="update_profile">
<div class="text-center mb-4">
<div class="position-relative d-inline-block">
<?php if (!empty($user['profile_picture'])): ?>
<img src="<?= e($user['profile_picture']) ?>" alt="<?= e(t('profile_picture')) ?>" class="rounded-circle shadow-sm object-fit-cover" style="width: 120px; height: 120px;">
<?php else: ?>
<div class="rounded-circle bg-light d-flex align-items-center justify-content-center shadow-sm" style="width: 120px; height: 120px;">
<i class="bi bi-person text-secondary" style="font-size: 4rem;"></i>
</div>
<?php endif; ?>
<label for="profile_picture" class="position-absolute bottom-0 end-0 bg-primary text-white rounded-circle p-2 cursor-pointer shadow" style="cursor: pointer;" title="<?= e(t('change_picture')) ?>">
<i class="bi bi-camera-fill"></i>
</label>
</div>
<input type="file" id="profile_picture" name="profile_picture" class="d-none" accept="image/jpeg,image/png,image/gif,image/webp" onchange="previewImage(this)">
<div class="small text-muted mt-2"><?= e(t('picture_hint')) ?></div>
</div>
<div class="mb-3">
<label class="form-label fw-bold"><?= e(t('full_name')) ?></label>
<input type="text" class="form-control form-control-lg" name="full_name" value="<?= e($user['full_name'] ?? '') ?>" required>
</div>
<div class="mb-3">
<label class="form-label fw-bold"><?= e(t('email_address')) ?></label>
<input type="email" class="form-control form-control-lg bg-light" value="<?= e($user['email'] ?? '') ?>" readonly disabled>
<div class="form-text"><?= e(t('email_hint')) ?></div>
</div>
<div class="mb-4">
<label class="form-label fw-bold"><?= e(t('account_role')) ?></label>
<input type="text" class="form-control form-control-lg bg-light text-capitalize" value="<?= e($user['role'] ?? '') ?>" readonly disabled>
</div>
<hr class="my-4">
<h4 class="mb-3"><?= e(t('change_password')) ?></h4>
<div class="mb-3">
<label class="form-label fw-bold"><?= e(t('new_password')) ?></label>
<input type="password" class="form-control form-control-lg" name="new_password" autocomplete="new-password">
</div>
<div class="mb-4">
<label class="form-label fw-bold"><?= e(t('confirm_password')) ?></label>
<input type="password" class="form-control form-control-lg" name="confirm_password" autocomplete="new-password">
</div>
<button type="submit" class="btn btn-primary btn-lg w-100 shadow-sm rounded-pill fw-bold">
<?= e(t('save_changes')) ?>
</button>
</form>
</div>
</div>
</div>
<script>
function previewImage(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
var imgContainer = input.previousElementSibling;
if (imgContainer.querySelector('img')) {
imgContainer.querySelector('img').src = e.target.result;
} else {
var newImg = document.createElement('img');
newImg.src = e.target.result;
newImg.className = 'rounded-circle shadow-sm object-fit-cover';
newImg.style.width = '120px';
newImg.style.height = '120px';
var iconDiv = imgContainer.querySelector('div');
if (iconDiv) {
iconDiv.replaceWith(newImg);
}
}
}
reader.readAsDataURL(input.files[0]);
}
}
</script>
<?php render_footer(); ?>