Если вы когда-нибудь задумывались, как устроена та самая «админка», через которую владельцы сайтов добавляют товары, пишут новости или меняют настройки, — эта статья для вас. Мы разберём, как создать простую, но рабочую админ-панель на PHP с нуля. Без сложных фреймворков и тонны библиотек — только то, что реально нужно для понимания логики и быстрого старта.

Digital-студия WNDER

Вы узнаете, как устроена структура панели, как защитить её от посторонних, как работать с базой данных и выводить данные в удобном виде. В конце — несколько лайфхаков, которые сэкономят вам часы работы.

С чего начать: структура и окружение

Представьте, что админ-панель — это отдельная комната в вашем доме, куда вы пускаете только проверенных гостей. Вход — через специальную дверь с замком (авторизация), а внутри — полки с инструментами (управление контентом).

Для разработки вам понадобится:

  • Веб-сервер (например, Apache или Nginx) с поддержкой PHP версии 7.4 и выше.
  • База данных MySQL или MariaDB.
  • Редактор кода (VS Code, Sublime Text или даже Блокнот, если вы мазохист).
  • Базовые знания PHP, SQL и HTML. Если вы знаете, как работает цикл foreach — уже хорошо.

Структура папок может выглядеть так:


/admin
    /login.php
    /dashboard.php
    /logout.php
    /config.php
    /includes/
        /db.php
        /functions.php
    /assets/
        /style.css
        /script.js

Всё, что относится к админке, лучше складывать в отдельную папку, чтобы не смешивать с публичной частью сайта. И не забудьте запретить доступ к ней через .htaccess или конфигурацию сервера.

Правило: никогда не храните пароли в открытом виде. Используйте функцию password_hash() для хеширования и password_verify() для проверки. Это как хранить ключ в сейфе, а не под ковриком.

Авторизация: контролируем вход

Первое, что нужно сделать, — это страница входа. Без неё админка будет открыта всем, кто знает URL. Согласитесь, это как оставить дверь в квартиру нараспашку.

Создадим простую форму входа. Вот пример файла login.php:


<?php
session_start();
require_once 'config.php';
require_once 'includes/db.php';

$error = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = trim($_POST['username'] ?? '');
    $password = $_POST['password'] ?? '';

    if ($username === '' || $password === '') {
        $error = 'Заполните все поля';
    } else {
        $stmt = $pdo->prepare('SELECT * FROM users WHERE username = ?');
        $stmt->execute([$username]);
        $user = $stmt->fetch();

        if ($user && password_verify($password, $user['password'])) {
            $_SESSION['user_id'] = $user['id'];
            $_SESSION['username'] = $user['username'];
            header('Location: dashboard.php');
            exit;
        } else {
            $error = 'Неверный логин или пароль';
        }
    }
}
?>
<!DOCTYPE html>
<html>
<head>
    <title>Вход в админку</title>
    <link rel="stylesheet" href="assets/style.css">
</head>
<body>
    <div class="login-form">
        <h2>Вход в панель управления</h2>
        <?php if ($error): ?>
            <p style="color: red;"><?= htmlspecialchars($error) ?></p>
        <?php endif; ?>
        <form method="post" action="">
            <label>Логин:</label>
            <input type="text" name="username" required>
            <label>Пароль:</label>
            <input type="password" name="password" required>
            <button type="submit">Войти</button>
        </form>
    </div>
</body>
</html>

Здесь мы используем PDO для работы с базой данных. Это удобно и безопасно, потому что PDO автоматически экранирует данные, защищая от SQL-инъекций.

Не забудьте создать таблицу users в базе данных. Пример SQL:


CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL
);

И добавить первого пользователя:


$hash = password_hash('admin123', PASSWORD_DEFAULT);
$stmt = $pdo->prepare('INSERT INTO users (username, password) VALUES (?, ?)');
$stmt->execute(['admin', $hash]);

Защита от незваных гостей: сессии и права

После входа нужно убедиться, что каждая страница админки проверяет, авторизован ли пользователь. Иначе любой сможет открыть dashboard.php напрямую.

Создадим функцию проверки в файле includes/functions.php:


function require_login() {
    if (session_status() === PHP_SESSION_NONE) {
        session_start();
    }
    if (empty($_SESSION['user_id'])) {
        header('Location: login.php');
        exit;
    }
}

Теперь в начале каждого файла админки вызываем эту функцию. Например, в dashboard.php:


<?php
require_once 'includes/functions.php';
require_login();
// Дальше код страницы
?>

Если пользователь не залогинен — он будет перенаправлен на страницу входа. Просто и эффективно.

Также стоит добавить проверку прав для разных ролей. Например, администратор может удалять записи, а редактор — только редактировать. Для этого в таблице users добавьте поле role, а в функции проверки учитывайте его.

МетодОписаниеКогда использовать
СессииХранение данных на сервереДля авторизации и временных данных
CookiesХранение данных на клиентеДля запоминания логина, но не пароля
JWTТокены с подписьюДля API и распределённых систем
Лайфхак: всегда используйте подготовленные выражения (prepare) при работе с базой данных. Это защищает от SQL-инъекций — одного из самых опасных видов атак.

Работа с базой данных: CRUD-операции

Админка без возможности добавлять, редактировать и удалять записи — как холодильник без еды. Бесполезно. Поэтому сделаем простой CRUD (Create, Read, Update, Delete) для какой-нибудь сущности, например, для новостей или товаров.

Создадим таблицу posts:


CREATE TABLE posts (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Теперь сделаем страницу для вывода списка записей — list.php:


<?php
require_once 'includes/db.php';
require_once 'includes/functions.php';
require_login();

$stmt = $pdo->query('SELECT * FROM posts ORDER BY created_at DESC');
$posts = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html>
<head>
    <title>Управление записями</title>
    <link rel="stylesheet" href="assets/style.css">
</head>
<body>
    <h2>Список записей</h2>
    <a href="create.php">Добавить новую</a>
    <table>
        <thead>
            <tr><th>ID</th><th>Заголовок</th><th>Дата</th><th>Действия</th></tr>
        </thead>
        <tbody>
        <?php foreach ($posts as $post): ?>
            <tr>
                <td><?= $post['id'] ?></td>
                <td><?= htmlspecialchars($post['title']) ?></td>
                <td><?= $post['created_at'] ?></td>
                <td>
                    <a href="edit.php?id=<?= $post['id'] ?>">Редактировать</a>
                    <a href="delete.php?id=<?= $post['id'] ?>" onclick="return confirm('Удалить?')">Удалить</a>
                </td>
            </tr>
        <?php endforeach; ?>
        </tbody>
    </table>
</body>
</html>

Обратите внимание на htmlspecialchars() при выводе заголовка. Это защищает от XSS-атак — когда злоумышленник вставляет скрипт в название записи.

Теперь создадим страницу создания записи — create.php:


<?php
require_once 'includes/db.php';
require_once 'includes/functions.php';
require_login();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $title = trim($_POST['title'] ?? '');
    $content = trim($_POST['content'] ?? '');

    if ($title === '' || $content === '') {
        $error = 'Заполните все поля';
    } else {
        $stmt = $pdo->prepare('INSERT INTO posts (title, content) VALUES (?, ?)');
        $stmt->execute([$title, $content]);
        header('Location: list.php');
        exit;
    }
}
?>
<!DOCTYPE html>
<html>
<head>
    <title>Добавить запись</title>
    <link rel="stylesheet" href="assets/style.css">
</head>
<body>
    <h2>Новая запись</h2>
    <?php if (isset($error)): ?>
        <p style="color: red;"><?= $error ?></p>
    <?php endif; ?>
    <form method="post" action="">
        <label>Заголовок:</label>
        <input type="text" name="title" required>
        <label>Текст:</label>
        <textarea name="content" rows="10" required></textarea>
        <button type="submit">Сохранить</button>
    </form>
</body>
</html>

Аналогично делаем edit.php и delete.php. В edit.php нужно подгрузить данные записи по ID и подставить в форму. В delete.php — просто удалить запись по ID после подтверждения.

Удобство использования: интерфейс и JS-улучшения

Голый HTML — это скучно. Добавим немного JavaScript, чтобы сделать админку удобнее. Например, можно сделать подтверждение удаления через модальное окно или динамическую подгрузку данных.

Вот пример простого скрипта, который добавляет класс «активный» к меню в зависимости от текущей страницы:


document.addEventListener('DOMContentLoaded', function() {
    const currentPage = window.location.pathname.split('/').pop();
    const menuLinks = document.querySelectorAll('.menu a');
    menuLinks.forEach(function(link) {
        if (link.getAttribute('href') === currentPage) {
            link.classList.add('active');
        }
    });
});

Также можно использовать JS для автоматического скрытия уведомлений или для валидации форм на стороне клиента. Но помните: JS-валидация — это только для удобства, безопасность должна обеспечиваться на сервере.

Не забывайте про CSS. Сделайте простой, но аккуратный стиль: белый фон, тёмный текст, кнопки с hover-эффектом. Вот пример CSS:


/* style.css */
body { font-family: Arial, sans-serif; margin: 20px; }
.login-form { max-width: 300px; margin: 0 auto; padding: 20px; border: 1px solid #ccc; }
input, textarea, button { width: 100%; margin-bottom: 10px; padding: 8px; }
button { background: #0073aa; color: white; border: none; cursor: pointer; }
button:hover { background: #005a87; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
.menu a { margin-right: 10px; }
.menu a.active { font-weight: bold; }
Правило: не смешивайте логику и представление. Выносите PHP-код в отдельные файлы, а HTML — в шаблоны. Это упростит поддержку и изменение кода.

Что в итоге: резюме

Мы создали основу админ-панели на PHP: авторизацию, защиту страниц, CRUD-операции и немного интерфейсных улучшений. Этого достаточно, чтобы понять принципы и расширять функционал под свои задачи.

Ключевые моменты, которые стоит запомнить:

  • Всегда используйте PDO с подготовленными выражениями для работы с базой.
  • Пароли храните только в хешированном виде.
  • Проверяйте авторизацию на каждой странице админки.
  • Экранируйте вывод данных, чтобы избежать XSS.
  • Разделяйте код и представление.

Теперь вы можете развивать эту панель: добавлять новые модули, настраивать права доступа, подключать AJAX и так далее. Главное — не бояться экспериментировать и искать оптимальные решения.

Если вы хотите сэкономить время и получить профессионально сделанную админ-панель, обратитесь в студию WNDER. Они знают, как сделать быстро и качественно.

Студия WNDER