218 lines
8.7 KiB
PHP
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(); ?>
|