09. Мини-проект: система заметок на PHP + MySQL + ООП
Введение
В этом уроке мы создадим простое, но полноценное приложение — Систему заметок. Пользователь сможет зарегистрироваться, войти и создавать свои заметки. Всё это — с использованием ООП, PDO и структуры MVC.Это уже не просто учебный пример — это мини-веб-приложение, как основа для будущего проекта или портфолио!
Что будет в проекте
- Регистрация и вход пользователя
- Создание, редактирование и удаление заметок (CRUD)
- Использование сессий и защита от XSS
- Структура MVC (Model-View-Controller)
Структура проекта
notes_app/
├── core/
│ ├── Database.php
│ └── Auth.php
├── models/
│ └── NoteModel.php
│ └── UserModel.php
├── controllers/
│ ├── NoteController.php
│ └── UserController.php
├── views/
│ ├── notes_list.php
│ ├── note_form.php
│ ├── login.php
│ └── register.php
└── index.php
Создание таблиц в MySQL
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL
);CREATE TABLE notes (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(200) NOT NULL,
text TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
Класс Database
<?php
class Database {
private $pdo;public function __construct() {
$this->pdo = new PDO('mysql:host=localhost;dbname=notes_app;charset=utf8mb4','root','');
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function query($sql, $params = []) {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt;
}
}
?>
Модель пользователя (UserModel)
<?php
class UserModel extends Database {
public function register($name, $email, $password) {
$hash = password_hash($password, PASSWORD_DEFAULT);
$this->query('INSERT INTO users (name,email,password) VALUES (?,?,?)', [$name,$email,$hash]);
}public function findByEmail($email) {
return $this->query('SELECT * FROM users WHERE email = ?', [$email])->fetch();
}
}
?>
Авторизация и сессии (Auth.php)
<?php
class Auth {
public static function start() {
if (session_status() === PHP_SESSION_NONE) session_start();
}public static function login($user) {
$_SESSION['user'] = $user;
}
public static function logout() {
session_destroy();
}
public static function user() {
return $_SESSION['user'] ?? null;
}
public static function check() {
return isset($_SESSION['user']);
}
}
?>
Контроллер пользователя (UserController)
<?php
require_once 'models/UserModel.php';
require_once 'core/Auth.php';class UserController {
public function register() {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'];
$email = $_POST['email'];
$pass = $_POST['password'];
$model = new UserModel();
$model->register($name,$email,$pass);
header('Location: index.php?action=login');
exit;
}
include 'views/register.php';
}
public function login() {
Auth::start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = $_POST['email'];
$pass = $_POST['password'];
$model = new UserModel();
$user = $model->findByEmail($email);
if ($user && password_verify($pass, $user['password'])) {
Auth::login($user);
header('Location: index.php?action=notes');
exit;
} else {
echo '<p style="color:red">Неверные данные</p>';
}
}
include 'views/login.php';
}
public function logout() {
Auth::logout();
header('Location: index.php?action=login');
}
}
?>
Модель заметок (NoteModel)
<?php
class NoteModel extends Database {
public function getAll($uid) {
return $this->query('SELECT * FROM notes WHERE user_id = ? ORDER BY id DESC', [$uid])->fetchAll();
}public function find($id, $uid) {
return $this->query('SELECT * FROM notes WHERE id = ? AND user_id = ?', [$id,$uid])->fetch();
}
public function create($title, $text, $uid) {
$this->query('INSERT INTO notes (title,text,user_id) VALUES (?,?,?)', [$title,$text,$uid]);
}
public function update($id, $title, $text, $uid) {
$this->query('UPDATE notes SET title=?, text=? WHERE id=? AND user_id=?', [$title,$text,$id,$uid]);
}
public function delete($id, $uid) {
$this->query('DELETE FROM notes WHERE id=? AND user_id=?', [$id,$uid]);
}
}
?>
Контроллер заметок (NoteController)
<?php
require_once 'models/NoteModel.php';
require_once 'core/Auth.php';class NoteController {
public function index() {
Auth::start();
$uid = Auth::user()['id'] ?? null;
if (!$uid) { header('Location: index.php?action=login'); exit; }
$model = new NoteModel();
$notes = $model->getAll($uid);
include 'views/notes_list.php';
}
public function create() {
Auth::start();
$uid = Auth::user()['id'] ?? null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
(new NoteModel())->create($_POST['title'], $_POST['text'], $uid);
header('Location: index.php?action=notes');
exit;
}
include 'views/note_form.php';
}
}
?>
Виды (Views)
views/login.php
<h2>Вход</h2>
<form method='post'>
<input name='email' placeholder='Email'><br>
<input name='password' type='password' placeholder='Пароль'><br>
<button>Войти</button>
</form>
<a href='index.php?action=register'>Регистрация</a>
views/register.php
<h2>Регистрация</h2>
<form method='post'>
<input name='name' placeholder='Имя'><br>
<input name='email' placeholder='Email'><br>
<input name='password' type='password' placeholder='Пароль'><br>
<button>Создать аккаунт</button>
</form>
<a href='index.php?action=login'>Уже есть аккаунт?</a>
views/notes_list.php
<h2>Мои заметки</h2>
<a href='index.php?action=create_note'>+ Новая заметка</a>
<hr>
<?php foreach ($notes as $n): ?>
<div style='border:1px solid #ccc; padding:10px; margin:10px 0;'>
<h3><?= htmlspecialchars($n['title']) ?></h3>
<p><?= nl2br(htmlspecialchars($n['text'])) ?></p>
<small>Создано: <?= htmlspecialchars($n['created_at']) ?></small>
</div>
<?php endforeach; ?>
views/note_form.php
<h2>Новая заметка</h2>
<form method='post'>
<input name='title' placeholder='Заголовок'><br>
<textarea name='text' placeholder='Текст заметки'></textarea><br>
<button>Сохранить</button>
</form>
<a href='index.php?action=notes'>Назад</a>
Файл index.php
<?php
require_once 'controllers/UserController.php';
require_once 'controllers/NoteController.php';action_router:
$action = $_GET['action'] ?? 'login';
$userController = new UserController();
$noteController = new NoteController();
switch ($action) {
case 'register': $userController->register(); break;
case 'login': $userController->login(); break;
case 'logout': $userController->logout(); break;
case 'notes': $noteController->index(); break;
case 'create_note': $noteController->create(); break;
default: echo 'Страница не найдена';
}
?>
Проверяем результат
1️⃣ Зарегистрируйтесь через форму регистрации. 2️⃣ Войдите под своими данными. 3️⃣ Добавьте заметку — она появится в списке. 4️⃣ Данные сохраняются в MySQL, каждая заметка связана с пользователем.Защита и советы
- Используйте htmlspecialchars() при выводе текста заметок
- Проверяйте сессию перед выполнением действий
- Пароли храните только в виде хэшей
- Добавьте проверку прав (uid == author_id)
Итоги урока
Вы создали:- Рабочую систему с регистрацией и авторизацией
- CRUD-операции для заметок
- Простую архитектуру MVC
- Классы для работы с БД, пользователями и заметками
- Мини-приложение, которое можно развивать дальше!