Первая запись в базе данных: форма на HTML + обработка на PHP

Разберём простой, но рабочий пример: как создать форму для добавления материала, автоматически генерировать slug из заголовка (с транслитерацией) и сохранить данные в базу через подготовленный запрос.


Что мы делаем

  • HTML‑форма — поля для заголовка, slug, описания, контента, чекбокс публикации.
  • JS‑логика — автоматически превращает заголовок в slug (кириллица → латиница), но даёт возможность править вручную. (Slug делает URL понятным для людей и полезным для SEO, обеспечивает уникальность в базе и даёт гибкость за счёт автогенерации с возможностью ручной правки.).
  • PHP‑обработчик — валидирует данные, нормализует slug, вставляет запись в БД через mysqli_prepare (защита от SQL‑инъекций).
  • Обратная связь — сообщение об успехе или ошибке.

Ниже — твои готовые фрагменты без правок и пояснения, как они работают вместе.


Форма (add-form.php) — интерфейс, который видит пользователь

html
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="utf-8">
    <title>Добавить материал</title>
    <link rel="stylesheet" href="site.css">
</head>
<body>
    <main class="container">
        <h2>Добавить материал</h2>
        <form method="POST" action="add_post.php">
            <label for="title">Заголовок (title)</label>
            <br><input type="text" name="title" id="title" required>
 
            <br><label for="slug">Slug (для URL, латиница и дефисы)</label>
            <br><small><span class="hint">Заполняется автоматически из заголовка (транслитерация). Можно отредактировать вручную.</span></small>
            <br><input type="text" name="slug" id="slug" required>
 
            <br><label for="excerpt">Краткое описание (excerpt, опционально)</label>
            <br><input type="text" name="excerpt" id="excerpt">
 
            <br><label for="content">Контент (content, можно HTML)</label>
            <br><textarea name="content" rows="10" cols="50" required></textarea>
 
            <br><input type="checkbox" name="is_published" id="is_published" value="1" checked>
            <label for="content">Опубликовать сразу (is_published)</label>
 
            <br><button class="btn-main">Добавить статью</button>
        </form>
    </main>
 
    <script>
        const titleInput = document.getElementById('title');
        const slugInput = document.getElementById('slug');
        let isManualEdit = false;
 
        // Если пользователь начал править slug вручную — перестаём его перезаписывать
        slugInput.addEventListener('input', () => {
            isManualEdit = true;
        });
 
        // Таблица транслитерации (кириллица → латиница)
        const translitMap = {
            'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',
            'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'y', 'к': 'k', 'л': 'l', 'м': 'm',
            'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',
            'ф': 'f', 'х': 'h', 'ц': 'ts', 'ч': 'ch', 'ш': 'sh', 'щ': 'sch',
            'ъ': '', 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya'
        };
 
        function transliterate(str) {
            return str
                .toLowerCase()
                .split('')
                .map(char => translitMap[char] || char)
                .join('');
        }
 
        titleInput.addEventListener('input', () => {
            if (isManualEdit) return;
 
            const value = titleInput.value.trim();
            if (!value) {
                slugInput.value = '';
                return;
            }
 
            // Транслитерация + очистка от лишних символов
            let slug = transliterate(value);
            slug = slug
                .replace(/[^a-z0-9]+/g, '-')      // оставляем только латиницу и цифры, остальное → дефис
                .replace(/^-+|-+\$/g, '')         // убираем дефисы в начале и конце
                .replace(/-+/g, '-');            // убираем множественные дефисы
 
            slugInput.value = slug;
        });
    </script>
</body>
</html>

Что тут важно для понимания процесса:

  • method="POST" и action="add_post.php" задают маршрут: данные уйдут на сервер в отдельный PHP‑файл.
  • Поля с name — это ключи, по которым PHP потом вытащит значения из $_POST.
  • JS не сохраняет данные в базу и не гарантирует формат slug — он только помогает пользователю.

Обработчик (add_post.php) — серверная часть без изменений

Код оставляем как есть, только добавляем короткие комментарии, где что происходит:

php
<?php
require 'db_connect.php';
 
// Проверка соединения с БД
if (!$connection || mysqli_connect_errno()) {
    http_response_code(500);
    echo 'Ошибка подключения к БД: ' . htmlspecialchars(mysqli_connect_error());
    exit;
}
 
$title          = trim($_POST['title'] ?? '');
$slug           = trim($_POST['slug'] ?? '');
$content        = $_POST['content'] ?? '';
$meta_desc      = $_POST['meta_description'] ?? null;
$meta_keys      = $_POST['meta_keywords'] ?? null;
$is_published   = isset($_POST['is_published']) ? 1 : 0;
$sort_order     = (int)($_POST['sort_order'] ?? 0);
 
// Валидация: title, slug, content обязательны
if ($title === '' || $slug === '' || $content === '') {
    http_response_code(400);
    echo 'Ошибка: поля title, slug и content обязательны.';
    exit;
}
 
// Нормализация slug: приводим к единому формату даже если пользователь ввёл что‑то странное
$slug = preg_replace('/[^a-z0-9\-]/i', '-', $slug);
$slug = preg_replace('/-+/', '-', $slug);
$slug = trim($slug, '-');
if ($slug === '') {
    $slug = 'page-' . time();
}
 
// SQL строго под CREATE TABLE pages
// created_at и updated_at не указываем — они заполняются автоматически (DEFAULT CURRENT_TIMESTAMP)
$sql = 'INSERT INTO posts (slug, title, content, meta_description, meta_keywords, is_published, sort_order)
        VALUES (?, ?, ?, ?, ?, ?, ?)';
 
$stmt = mysqli_prepare($connection, $sql);
if (!$stmt) {
    http_response_code(500);
    echo 'Ошибка подготовки запроса: ' . htmlspecialchars(mysqli_error($connection));
    exit;
}
 
// Типы: s=строка, i=число. Порядок строго как в INSERT
if (!mysqli_stmt_bind_param($stmt, 'ssssssi', $slug, $title, $content, $meta_desc, $meta_keys, $is_published, $sort_order)) {
    http_response_code(500);
    echo 'Ошибка привязки параметров: ' . htmlspecialchars(mysqli_stmt_error($stmt));
    mysqli_stmt_close($stmt);
    exit;
}
 
if (mysqli_stmt_execute($stmt)) {
    $new_id = mysqli_insert_id($connection);
    echo "Статья успешно добавлена! ID записи: $new_id";
} else {
    http_response_code(500);
    echo 'Ошибка при добавлении записи: ' . htmlspecialchars(mysqli_stmt_error($stmt));
}
 
mysqli_stmt_close($stmt);
?>

После добавления записи в базу данных мы видим следующее:

Запись в базе данных:

Как это всё складывается в «первую запись»

  1. Пользователь открывает форму, вводит заголовок — JS сразу показывает готовый slug.
  2. Пользователь может поправить slug вручную; тогда автозаполнение отключается.
  3. После отправки формы данные приходят в add_post.php в массиве $_POST.
  4. PHP проверяет, что обязательные поля не пустые.
  5. PHP дополнительно «чистит» slug регулярками — на случай, если пользователь ввёл недопустимые символы.
  6. Выполняется подготовленный запрос INSERT INTO posts … — так в таблице появляется первая строка.
  7. Скрипт выводит сообщение и ID новой записи.

Добавить комментарий