BlockifyPHP — безопасность структуры данных блочного редактора

48
09 сентября 2025
BlockifyPHP — безопасность структуры данных блочного редактора

Доброго времени суток! Хочу поделиться радостной новостью! Недавно я успешно завершил разработку и довел до производственной готовности проект @texditor/editor — мощного и легкого блочного редактора контента. И самое крутое то, что его уже можно «пощупать». На данный момент он интегрирован на этом сайте и именно с его помощью написано это сообщение! Редактор достиг стабильной версии, которую я считаю сильным базовым релизом. Хотя документация еще в процессе разработки 😄, первый серьезный шаг сделан!

Преодоление вызовов

Честно признаюсь, этот проект дался мне невероятно тяжело. Я погнался за двумя зайцами: хотел создать редактор с идеально современным, интуитивным интерфейсом и при этом начинить его всеми мыслимыми функциями. Эта гонка за идеалом на стыке юзабилити и функциональности оказалась настоящим испытанием, но невероятно продуктивной.

Интеграция и тестирование

Переход от тестирования к реальной эксплуатации редактора выявил серьезные проблемы, связанные с безопасностью, валидацией входящих данных и целостностью их структуры. Стандартных методов, таких как экранирование и последовательная очистка блоков, оказалось недостаточно для гарантии надежности. Осознавая ответственность не только за свои проекты, но и за продукты других разработчиков, я принял решение о разработке специализированной библиотеки. Её ключевыми функциями стали комплексная фильтрация, строгая валидация, обеспечение структурной целостности данных и рендеринг в чистый HTML для сторонников классического подхода.

Для тех кому уже не терпится, проект расположен на github https://github.com/texditor/blockify-php или установку через composer.

composer require texditor/blockify-php

Структура

После тщательного анализа десятков возможных архитектурных решений я остановился на варианте, который сочетает в себе простоту реализации и современный, элегантный синтаксис.

src/
├── Exceptions/          # Специализированные исключения
├── Interfaces/          # Фундаментальные интерфейсы
│   ├── ConfigInterface.php
│   ├── BlockModelInterface.php
│   └── RenderableInterface.php
├── Models/              # Модели блоков с правилами обработки
├── Blockify.php         # Основной класс-обработчик
├── BlockModel.php       # Базовая модель блока
├── Config.php           # Единый источник конфигурации
└── HtmlBuilder.php      # Рендерер HTML

Модели блоков

Приоритетными направлениями были объявлены простота установки и расширение функционала для обработки блочных моделей:

<?php

namespace Texditor\Blockify\Models;

use Texditor\Blockify\BlockModel;

class CodeBlock extends BlockModel
{
    protected string $inputName = 'code';
    protected string $outputName = 'pre';
    protected array $allowedTags = [];
    protected bool $isPreformatted = true;
}

По сути это и есть готовая модель, которую можно сразу использовать. "Под капотом" у неё уже есть множество методов, так как она наследует их от BlockModel. Чтобы сделать модель идеально подходящей для ваших нужд, просто создайте на её основе свой класс и внесите нужные правки.

Использование

Библиотека реализована таким образом, что её можно использовать как в среде с сервис-контейнерами (например, в рамках Laravel, Symfony), так и в стандартных PHP-условиях с обычным инстанцированием классов (пример взят из Github).

<?php
use Texditor\Blockify\Blockify;
use Texditor\Blockify\Config;
use Texditor\Blockify\Models\ParagraphBlock;
use Texditor\Blockify\Models\CodeBlock;
use Texditor\Blockify\Models\FilesBlock;
use Texditor\Blockify\Models\GalleryBlock;
use Texditor\Blockify\Models\HeaderBlock;
use Texditor\Blockify\Models\OrderedListBlock;
use Texditor\Blockify\Models\UnorderedListBlock;


// Создаем конфигурацию и добавляем модели блоков
$config = (new Config())
    ->addModels(
        (new ParagraphBlock())
          ->setAllowedTags(['a', 'b']),
        new CodeBlock(),
        (new FilesBlock())
            ->setSourceProtocols(['https', 'http'])
            ->setSourceProtocols(['https', 'http'])
            // or only locally
            ->setSourceRegex(["/^\/uploads\/.*\.(png|jpg|jpeg|gif)$/"]),
        (new GalleryBlock())
            // ->setIsMeta(true)
            // ->setIsMetaCaption(true)
            // ->setIsMetaDesc(false)
            ->setMetaPosition('top')
            ->setImageTypes(['image/png', 'image/jpeg'])
            ->setVideoTypes(['video/mp4'])
            ->setVideoAttributes([
                'controls' => 'true'
            ]),

        new UnorderedListBlock(),
        new OrderedListBlock(),
        // Default h1
        new HeaderBlock(),
        (new HeaderBlock())
            ->setOutputName('h2')
            ->setInputName('h2'),
            //... 
    );

// Получаем данные в виде строки
$jsonData = $_POST['data'] ?? '';

// Запускаем процесс чистки и валидации
$blockify = (new Blockify($config))
    ->setData($jsonData);


// Получаем безопасные данные

$blocks = $blockify->getData();

Рассмотрим в сравненнии с обычным HTML-кодом:

<!-- И из простого "Привет мир" (даже с большим количеством пробелов)-->
<p>Привет мир!    <script>alert();</script></p>
// Получаем JSON со списком блоков
[
    {
        "type": "p"
        "data": "Привет мир <script>alert();</script>"
    } 
]
// и разумеется все теги будут экранированы, т.к не являются частью структуры данных

Добавив в параграф дополнительные данные, такие как полужирный текст, мы получаем массив с несколькими уровнями вложенности, отражающий иерархическую структуру контента.

<h2>Заголовок</h2>
<p>Привет мир! Добавим не много <b>жирного</b> в наш рацион.</p>
<pre><?php echo</pre>
[
    {
        "type" : "h2",
        "data" : [
            "Заголовок"
        ]
    },
    {
        "type" : "p",
        "data" : [
            "Привет мир! Добавим не много ",
            {
                "type" : "b",
                "data" : [
                    "жирного "
                ]
            },
            "в наш рацион."
        ]
    },
    // Эти данные будут экранированы
    {
        "type" : "code",
        "data" : [
            "&lt?php echo"
        ]
    }
]

Заключение

Blockify PHP — это получилась не просто библиотека безопасности, а комплексное решение для работы с структурированным контентом. Она покрывает более 90% типичных требований при работе с данными редактора контента, обеспечивая:

  • 🔒 Безопасность: Многоуровневая защита от XSS и инъекций
  • 🏗️ Структуру: Четкая семантическая организация контента
  • 🔧 Гибкость: Легкое расширение и кастомизация
  • 🚀 Производительность: Оптимизированная обработка больших данных
  • 🔌 Интегрируемость: Работа с любым PHP-фреймворком
Комментарии 0

Нет элементов для отображения

Только зарегистрированные пользователи могут оставлять комментарии Войти

Рекомендуем
Легкий кастомный компонент маскировщика номера телефона и email на React+TypeScript для Российского формата
14
22 октября 2025

Простое, быстрое и функциональное решение для маскировки номера телефона в Российском формате или электронного адреса.

Привет, мир! или давайте знакомиться с веб-технологиями
64
09 сентября 2025

Веб-разработка — это как собрать сложный, но невероятно красивый пазл