Реализация функционала добавления контентных страниц в PHP

Раздел: Управление контентом -> Добавление страниц

Способы добавления страниц в PHP

Добавление новых страниц на сайт – одна из ключевых задач управления контентом. В PHP существует несколько подходов к реализации этого функционала. Выбор метода зависит от архитектуры проекта, требований к производительности и безопасности. Рассмотрим основные варианты.

Решение с использованием базы данных (рекомендуемое)

Этот способ предполагает хранение страниц в реляционной базе данных, например MySQL. Создается таблица pages с полями id, title, slug, content, created_at. Алгоритм: форма ввода, PHP-обработчик с PDO, вставка записи.

Пример формы (файл add_page.html):


<form method='post' action='add_page.php'>
  <input type='text' name='title' placeholder='Заголовок' required>
  <input type='text' name='slug' placeholder='URL (например, about)' required>
  <textarea name='content' required></textarea>
  <button type='submit'>Добавить страницу</button>
</form>

Add php page (добавить страницу php)

Обработчик add_page.php:


<?php
$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'pass');
$stmt = $pdo->prepare('INSERT INTO pages (title, slug, content) VALUES (?, ?, ?)');
$stmt->execute([$_POST['title'], $_POST['slug'], $_POST['content']]);
header('Location: success.php');

Пояснения: подготовленный запрос защищает от SQL-инъекций. После вставки выполняется редирект.

Типичные проблемы:

  • SQL инъекция при отсутствии экранирования. Решение – использование подготовленных выражений (PDO).
  • Дублирование slug. Необходимо проверять уникальность перед вставкой.
  • XSS атаки при выводе контента. При сохранении не фильтровать, а при выводе использовать htmlspecialchars.

Вариант 1: Хранение страниц в файловой системе

Как создать страницу без базы данных, сохраняя её в файл?

В этом методе каждая страница – отдельный PHP-файл в определённой директории. Форма принимает название файла и содержимое, обработчик создаёт файл с помощью file_put_contents.


<?php
$filename = $_POST['slug'] . '.php';
$content = '<?php // страница ' . $_POST['title'] . ' ?>' . PHP_EOL . $_POST['content'];
file_put_contents('pages/' . $filename, $content);
echo 'Страница создана';

Проблемы:

  • Пользователь может вставить PHP-код, что приведёт к выполнению произвольного кода. Решение – отключать интерпретацию PHP в сохранённых файлах (например, хранить как .html или использовать фильтрацию).
  • Конфликты имён файлов. Проверять существование с помощью file_exists.
  • Права доступа – веб-сервер должен иметь право на запись.

Вариант 2: Использование шаблонизатора Twig

Как отделить логику от представления при добавлении страниц?

Twig позволяет создавать шаблоны, в которые передаются данные. Страница может сохраняться в БД как шаблон или как данные, затем рендериться.


<?php
require_once 'vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader);
// Сохраняем шаблон content.html.twig в БД или файл
$template = '<h1>{{ title }}</h1><p>{{ content }}</p>';
file_put_contents('templates/' . $slug . '.html.twig', $template);
// При выводе
echo $twig->render($slug . '.html.twig', ['title' => $title, 'content' => $content]);

Проблемы:

  • Необходимость компиляции шаблонов при каждом изменении. Использовать кэш Twig.
  • Сложность для простых проектов.

Вариант 3: Интеграция с WordPress

Как добавить страницу в WordPress через PHP-код?

WordPress предоставляет функцию wp_insert_post. Необходимо предварительно загрузить среду WordPress (wp-load.php).


<?php
require_once('wp-load.php');
$post_data = array(
  'post_title'    => 'Новая страница',
  'post_content'  => 'Текст страницы',
  'post_status'   => 'publish',
  'post_type'     => 'page'
);
$post_id = wp_insert_post($post_data);
if ($post_id) echo 'Страница создана с ID ' . $post_id;

Проблемы:

  • Прямой вызов wp-load.php может конфликтовать с буферизацией вывода.
  • Необходимость обновления постоянных ссылок (flush_rewrite_rules).
  • Обработка мета-полей и произвольных таксономий.

Вариант 4: Использование фреймворка Laravel

Как добавить страницу через Eloquent ORM в Laravel?

Laravel предлагает миграции, модели и валидацию. Пример контроллера:


<?php
namespace App\Http\Controllers;
use App\Models\Page;
use Illuminate\Http\Request;

class PageController extends Controller
{
    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'slug'  => 'required|string|unique:pages',
            'content' => 'required|string'
        ]);
        Page::create($validated);
        return redirect('/pages')->with('success', 'Страница добавлена');
    }
}

Проблемы:

  • Необходимость настройки маршрутов и CSRF-защиты.
  • Обработка ошибок валидации (возврат ошибок в JSON или сессию).

Вариант 5: REST API для добавления страниц

Как добавить страницу через внешний API-запрос?

Сервер принимает JSON, обрабатывает и возвращает ответ. Пример на чистом PHP:


<?php
header('Content-Type: application/json');
$input = json_decode(file_get_contents('php://input'), true);
if (!$input || empty($input['title'])) {
    http_response_code(400);
    echo json_encode(['error' => 'Неверные данные']);
    exit;
}
// сохранение в БД
$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'pass');
$stmt = $pdo->prepare('INSERT INTO pages (title, slug, content) VALUES (?, ?, ?)');
$stmt->execute([$input['title'], $input['slug'], $input['content']]);
echo json_encode(['id' => $pdo->lastInsertId(), 'status' => 'ok']);

Проблемы:

  • Отсутствие аутентификации. Добавлять проверку API-ключа.
  • Обработка CORS для кросс-доменных запросов.
  • Ограничение размера запроса и защита от повторной отправки.

Расширенные примеры реализации

Пример 1: Продвинутая обработка формы с CSRF, валидацией и транзакцией

Форма содержит скрытое поле с CSRF-токеном из сессии. Обработчик проверяет токен, использует PDO-транзакцию для атомарности, проверяет уникальность slug перед вставкой.

Пример

// Форма (add_page.php)
<form method='post' action=''>
    <input type='hidden' name='csrf_token' value='<?php echo $_SESSION['csrf_token']; ?>'>
    <input type='text' name='title' required>
    <input type='text' name='slug' required>
    <textarea name='content'></textarea>
    <button type='submit'>Добавить</button>
</form>

// Обработчик (тот же файл)
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
        die('CSRF-токен неверный');
    }
    $pdo = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'pass', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ]);
    try {
        $pdo->beginTransaction();
        // Проверка уникальности slug
        $check = $pdo->prepare('SELECT COUNT(*) FROM pages WHERE slug = ?');
        $check->execute([$_POST['slug']]);
        if ($check->fetchColumn() > 0) {
            throw new Exception('Slug уже существует');
        }
        $stmt = $pdo->prepare('INSERT INTO pages (title, slug, content, created_at) VALUES (?, ?, ?, NOW())');
        $stmt->execute([$_POST['title'], $_POST['slug'], $_POST['content']]);
        $pdo->commit();
        echo 'Страница создана с ID ' . $pdo->lastInsertId();
    } catch (Exception $e) {
        $pdo->rollBack();
        echo 'Ошибка: ' . $e->getMessage();
    }
}
Страница создана с ID 42

Пример 2: Автоматическая генерация уникального slug из заголовка

Функция транслитерации кириллицы в латиницу, затем проверка в БД и добавление суффикса при дубликате.

Пример

function generateSlug($string, $pdo) {
    $slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $string), '-'));
    // Транслитерация для кириллицы
    $translit = array(
        'а'=>'a','б'=>'b','в'=>'v','г'=>'g','д'=>'d','е'=>'e','ё'=>'yo','ж'=>'zh',
        'з'=>'z','и'=>'i','й'=>'y','к'=>'k','л'=>'l','м'=>'m','н'=>'n','о'=>'o',
        'п'=>'p','р'=>'r','с'=>'s','т'=>'t','у'=>'u','ф'=>'f','х'=>'kh','ц'=>'ts',
        'ч'=>'ch','ш'=>'sh','щ'=>'shch','ы'=>'y','э'=>'e','ю'=>'yu','я'=>'ya'
    );
    $slug = strtr($string, $translit);
    $slug = preg_replace('/[^A-Za-z0-9-]+/', '-', $slug);
    $slug = trim($slug, '-');
    $original = $slug;
    $i = 0;
    while (true) {
        $check = $pdo->prepare('SELECT COUNT(*) FROM pages WHERE slug = ?');
        $check->execute([$slug]);
        if ($check->fetchColumn() == 0) break;
        $i++;
        $slug = $original . '-' . $i;
    }
    return $slug;
}
// Использование:
$slug = generateSlug($_POST['title'], $pdo);
При заголовке 'О нас' вернёт 'o-nas'

Пример 3: Сохранение страницы с поддержкой нескольких языков

Таблица pages содержит только id и created_at. Таблица page_translations содержит page_id, locale, title, content. Форма с выбором языка.

Пример

// Создание таблиц
CREATE TABLE pages (
  id INT AUTO_INCREMENT PRIMARY KEY,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE page_translations (
  id INT AUTO_INCREMENT PRIMARY KEY,
  page_id INT NOT NULL,
  locale VARCHAR(5) NOT NULL,
  title VARCHAR(255) NOT NULL,
  content TEXT NOT NULL,
  FOREIGN KEY (page_id) REFERENCES pages(id) ON DELETE CASCADE
);

// Обработчик
$pdo->beginTransaction();
$stmt = $pdo->prepare('INSERT INTO pages () VALUES ()');
$stmt->execute();
$pageId = $pdo->lastInsertId();
$stmt = $pdo->prepare('INSERT INTO page_translations (page_id, locale, title, content) VALUES (?, ?, ?, ?)');
foreach ($_POST['translations'] as $locale => $data) {
    $stmt->execute([$pageId, $locale, $data['title'], $data['content']]);
}
$pdo->commit();
Страница 5 создана с переводами ru, en

Пример 4: Добавление страницы через API с аутентификацией по токену

API-ключ передается в заголовке Authorization. Сервер проверяет его в таблице api_keys, затем обрабатывает JSON.

Пример

<?php
header('Content-Type: application/json');
$apiKey = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'pass');
$check = $pdo->prepare('SELECT id FROM api_keys WHERE `key` = ? AND active = 1');
$check->execute([$apiKey]);
if (!$check->fetch()) {
    http_response_code(401);
    echo json_encode(['error' => 'Неверный API-ключ']);
    exit;
}
$input = json_decode(file_get_contents('php://input'), true);
if (!$input || empty($input['title'])) {
    http_response_code(400);
    echo json_encode(['error' => 'Отсутствует заголовок']);
    exit;
}
$stmt = $pdo->prepare('INSERT INTO pages (title, slug, content) VALUES (?, ?, ?)');
$stmt->execute([$input['title'], $input['slug'] ?? '', $input['content'] ?? '']);
echo json_encode(['status' => 'ok', 'id' => $pdo->lastInsertId()]);
{"status":"ok","id":101}

Пример 5: Кэширование готовых страниц для ускорения вывода

При сохранении страницы обновляется кэш. При запросе сначала проверяется кэш-файл, и если он актуален, выводится без выполнения PHP.

Пример

// Функция отображения страницы с кэшем
function showPage($slug, $pdo) {
    $cacheFile = __DIR__ . '/cache/' . $slug . '.html';
    $cacheTime = 3600; // 1 час
    // Если кэш существует и не устарел
    if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < $cacheTime)) {
        readfile($cacheFile);
        return;
    }
    // Иначе получаем из БД
    $stmt = $pdo->prepare('SELECT title, content FROM pages WHERE slug = ?');
    $stmt->execute([$slug]);
    $page = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$page) {
        http_response_code(404);
        echo 'Страница не найдена';
        return;
    }
    ob_start();
    echo '<h1>' . htmlspecialchars($page['title']) . '</h1>';
    echo '<div>' . $page['content'] . '</div>';
    $html = ob_get_clean();
    file_put_contents($cacheFile, $html);
    echo $html;
}
// При создании/обновлении страницы нужно очищать кэш:
$cacheFile = __DIR__ . '/cache/' . $slug . '.html';
if (file_exists($cacheFile)) unlink($cacheFile);
Страница отображается из кэша, время загрузки < 0.01 сек

Добавить страницу PHP - comments

En
Add php page (php)