PHP разработка личной страницы пользователя
Создание страницы профиля пользователя на PHP
Основной подход: работа через PDO и сессии
Наиболее эффективное решение строится на использовании PDO для работы с базой данных (MySQL) и сессий для аутентификации. Это обеспечивает безопасность, гибкость и переносимость кода.
Структура проекта
- config.php - настройки подключения к БД, константы
- functions.php - вспомогательные функции (фильтрация, хеширование)
- login.php - форма и обработка входа
- register.php - регистрация нового пользователя
- profile.php - страница профиля (основная)
- logout.php - выход из системы
Ключевые шаги
- Создание базы данных и таблицы users (id, username, email, password_hash, avatar, created_at).
- Настройка PDO-соединения в config.php.
- Регистрация пользователя с хешированием пароля (password_hash()).
- Авторизация через проверку хеша (password_verify()) и запись в сессию.
- Вывод данных профиля только для авторизованных пользователей.
- Обработка ошибок с помощью исключений PDO.
Пример кода для config.php:
<?php
session_start();
const DB_HOST = 'localhost';
const DB_NAME = 'site_db';
const DB_USER = 'root';
const DB_PASS = '';
try {
$pdo = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=utf8", DB_USER, DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die('Ошибка подключения: ' . $e->getMessage());
}
?>
Типичные ошибки
- Забыли вызвать session_start() - данные сессии не будут доступны.
- Неправильный DSN или учётные данные - исключение PDO ловится, но иногда разработчики не обрабатывают ошибку.
- Не указан charset - возникает проблема с кириллицей.
- Использование устаревшего расширения mysql_* (оно удалено из PHP 7).
Как сделать страницу профиля без базы данных, используя файлы?
Для небольших проектов или прототипов можно хранить данные в JSON-файлах. Каждый пользователь - отдельный файл users/{id}.json. Авторизация через сессию, пароль хешируется. Минусы: нет параллельного доступа, медленно при большом количестве записей.
Пример создания пользователя в файле:
$userData = [
'username' => $_POST['username'],
'password' => password_hash($_POST['password'], PASSWORD_DEFAULT),
'email' => $_POST['email']
];
$id = uniqid();
file_put_contents("users/$id.json", json_encode($userData));
Проблема
При одновременной записи двух скриптов возможна потеря данных. Решается блокировкой файла через flock(), но это снижает производительность.
Как интегрировать страницу профиля в фреймворк Laravel для быстрой разработки?
Laravel предоставляет готовую систему аутентификации (make:auth), Eloquent ORM и Blade-шаблоны. Достаточно выполнить php artisan make:auth и настроить маршруты. Личная страница пользователя может быть выведена через контроллер с middleware 'auth'. Пример контроллера:
class ProfileController extends Controller
{
public function show()
{
$user = Auth::user();
return view('profile.show', compact('user'));
}
}
Ошибка новичков
Неверное указание middleware в маршруте приводит к тому, что страница доступна без авторизации. Правильно: Route::get('/profile', 'ProfileController@show')->middleware('auth');
Как использовать шаблонизатор Twig вместо встроенного PHP для профиля?
Twig позволяет разделить логику и представление. Пример шаблона profile.twig:
{% extends 'base.twig' %}
{% block content %}
<h2>Профиль пользователя {{ user.username }}</h2>
<p>Email: {{ user.email }}</p>
<img src="{{ user.avatar }}" alt="Аватар">
{% endblock %}
Типичная проблема
Неэкранированный вывод через Twig по умолчанию безопасен, но если разработчик использует raw-фильтр без необходимости - появляется XSS-уязвимость.
Как реализовать профиль через mysqli, не используя PDO?
Mysqli также поддерживает подготовленные запросы. Код похож на PDO, но объектно-ориентированный синтаксис другой. Пример:
$mysqli = new mysqli('localhost', 'root', '', 'site_db');
$stmt = $mysqli->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param('i', $_SESSION['user_id']);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
Распространённая ошибка
Забывают проверить количество строк: $result->num_rows. Если результат пуст, обращение к $user вызовет ошибку.
Расширенные примеры кода для страницы пользователя
1. Полная регистрация с валидацией и обработкой ошибок
<?php
require_once 'config.php';
$errors = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username'] ?? '');
$email = trim($_POST['email'] ?? '');
$password = $_POST['password'] ?? '';
$passwordConfirm = $_POST['password_confirm'] ?? '';
if (strlen($username) < 3) $errors[] = 'Логин должен быть не менее 3 символов';
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $errors[] = 'Некорректный email';
if (strlen($password) < 6) $errors[] = 'Пароль должен быть не менее 6 символов';
if ($password !== $passwordConfirm) $errors[] = 'Пароли не совпадают';
// Проверка уникальности
if (empty($errors)) {
$stmt = $pdo->prepare("SELECT id FROM users WHERE username = ? OR email = ?");
$stmt->execute([$username, $email]);
if ($stmt->rowCount() > 0) $errors[] = 'Пользователь с таким логином или email уже существует';
}
if (empty($errors)) {
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (username, email, password_hash) VALUES (?, ?, ?)");
$stmt->execute([$username, $email, $hash]);
$_SESSION['user_id'] = $pdo->lastInsertId();
header('Location: profile.php');
exit;
}
}
?>
<form method="post">
<!-- поля -->
</form>
<?php foreach ($errors as $error): ?>
<p><?= htmlspecialchars($error) ?></p>
<?php endforeach; ?>
2. Безопасный вывод профиля с защитой от XSS
<?php
require_once 'config.php';
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
?>
<h2>Профиль</h2>
<p>Имя: <?= htmlspecialchars($user['username']) ?></p>
<p>Email: <?= htmlspecialchars($user['email']) ?></p>
<p>Дата регистрации: <?= htmlspecialchars($user['created_at']) ?></p>
3. Обновление данных профиля (смена email)
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['new_email'])) {
$newEmail = trim($_POST['new_email']);
if (filter_var($newEmail, FILTER_VALIDATE_EMAIL)) {
$stmt = $pdo->prepare("UPDATE users SET email = ? WHERE id = ?");
$stmt->execute([$newEmail, $_SESSION['user_id']]);
$success = 'Email обновлён';
} else {
$error = 'Некорректный email';
}
}
?>
<?php if (isset($success)): ?>
<p class="success"><?= $success ?></p>
<?php endif; ?>
<?php if (isset($error)): ?>
<p class="error"><?= htmlspecialchars($error) ?></p>
<?php endif; ?>
4. Загрузка аватара с проверкой типа и размера
<?php
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
$maxSize = 2 * 1024 * 1024; // 2 MB
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['avatar'])) {
$file = $_FILES['avatar'];
if ($file['error'] !== UPLOAD_ERR_OK) {
$error = 'Ошибка при загрузке файла';
} elseif (!in_array($file['type'], $allowedTypes)) {
$error = 'Допустимы только JPEG, PNG, GIF';
} elseif ($file['size'] > $maxSize) {
$error = 'Файл слишком большой (макс. 2 МБ)';
} else {
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$newName = $_SESSION['user_id'] . '_' . uniqid() . '.' . $ext;
move_uploaded_file($file['tmp_name'], 'uploads/avatars/' . $newName);
$stmt = $pdo->prepare("UPDATE users SET avatar = ? WHERE id = ?");
$stmt->execute([$newName, $_SESSION['user_id']]);
$success = 'Аватар обновлён';
}
}
?>
5. Вывод списка пользователей (админ-панель)
<?php
$stmt = $pdo->query("SELECT id, username, email, created_at FROM users ORDER BY created_at DESC");
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<table>
<tr><th>ID</th><th>Логин</th><th>Email</th><th>Дата</th></tr>
<?php foreach ($users as $u): ?>
<tr>
<td><?= $u['id'] ?></td>
<td><?= htmlspecialchars($u['username']) ?></td>
<td><?= htmlspecialchars($u['email']) ?></td>
<td><?= $u['created_at'] ?></td>
</tr>
<?php endforeach; ?>
</table>
Результат выполнения (пример для п.4 - загрузка аватара)
После успешной загрузки файла avatar_1_60f5a2b3c4d5e.jpg появляется в папке uploads/avatars/. В таблице users в поле avatar записывается имя файла. При выводе профиля используется <img src="uploads/avatars/<?= $user['avatar'] ?>">.