Search by

cloud-castle / serialize

alex-4-17

Безопасная сериализация для PHP 8.1+: PHP/JSON/igbinary из одного API, HMAC-подпись, белый список классов и лимит размера при десериализации, маппинг объект↔массив и экспорт в PHP-код. Нулевые внешние зависимости.

v1.2.1 2026-07-27 20:41 UTC

README

🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano

CloudCastle Serialize

CloudCastle Serialize

Packagist Version PHP Version License Downloads Monthly Downloads Stars Dependents Suggesters

Репозиторий Пайплайны Задачи Релизы Wiki Обсуждения

PHPStan Psalm PHPMD PHPCS Coverage Infection MSI OpenSSF Scorecard

Один API для восьми форматов сериализации PHP с безопасностью по умолчанию: объекты не восстанавливаются без явного разрешения, а нагрузку можно подписать, зашифровать, сжать и ограничить сроком жизни. Нулевые обязательные зависимости.

Установка

composer require cloud-castle/serialize

Требуется PHP 8.1+. Форматы igbinary и MessagePack используют одноимённые расширения; всё остальное работает на стандартной сборке PHP.

Быстрый старт

<?php

use CloudCastle\Serialize\Context;
use CloudCastle\Serialize\Serializer;

// PHP-формат: объекты запрещены по умолчанию (защита от gadget-chain).
$payload = Serializer::php([Order::class])->serialize($order);
$order   = Serializer::php([Order::class])->unserialize($payload);

// Восемь форматов за одним интерфейсом.
$json   = Serializer::json()->serialize($data);
$xml    = Serializer::xml()->serialize($data);          // типы не теряются
$csv    = Serializer::csv()->serialize($rows);
$yaml   = Serializer::yaml()->serialize($config);
$ndjson = Serializer::ndjson()->serialize($collection); // построчный поток

// Защита нагрузки собирается композицией: подпись, TTL, сжатие, шифрование.
$token  = Serializer::signed($key, Serializer::expiring(3600, Serializer::json()));
$sealed = $token->seal(['user' => 42]);
$data   = $token->unseal($sealed);   // подделка и просрочка отклоняются до разбора

// Анонимные функции и объекты анонимных классов — на любой глубине структуры.
$codec = Serializer::dynamic($key);
$payload = $codec->serialize([
    'handler' => static fn (int $x): int => $x * 2,
    'policy'  => new class { public int $limit = 10; },
]);
$data = $codec->unserialize($payload);
$data['handler'](21);      // 42
$data['policy']->limit;    // 10

// Маппинг объектов: группы, версии схемы, маскирование персональных данных.
$public = Serializer::mapper()->toArray($order, Context::create()->withGroups(['public']));
$safe   = Serializer::mapper()->toArray($order, Context::forLogging()); // ПД замаскированы
$order  = Serializer::mapper()->fromArray(Order::class, $public);

Возможности

  • Восемь форматов за единым интерфейсом: PHP, JSON, XML, CSV, YAML, NDJSON, igbinary, MessagePack — плюс экспорт в исполняемый PHP-код.
  • Безопасность по умолчанию: объекты не восстанавливаются без белого списка, размер и глубина нагрузки ограничены, XML отклоняет DTD, распаковка архива лимитирована.
  • Защита нагрузки композицией: HMAC-подпись с ротацией ключей, шифрование XSalsa20-Poly1305, срок жизни, прозрачное сжатие — в любых сочетаниях.
  • Маппинг объект ↔ массив на атрибутах: группы, версии схемы, стратегии именования, типизированные коллекции, полиморфизм, маскирование ПД для логов.
  • Потоковая обработка коллекций: запись и чтение по одному элементу — пиковая память не зависит от размера набора.
  • Анонимные функции и объекты анонимных классов переносятся сквозь любую структуру — с обязательной подписью кода, поскольку нагрузка исполняемая.
  • Ноль обязательных зависимостей — ни одной транзитивной уязвимости.

Описание каждой возможности с примерами, диаграммами и сравнением с аналогами — в wiki.

Сравнение с аналогами

Все таблицы ниже сгенерированы автоматически из честных сравнительных прогонов (benchmarks/compare.php): каждое решение выполняет одинаковую работу на PHP 8.1.34 без Xdebug.

1. Функциональность

ВозможностьCloudCastlesymfony/serializerjms/serializervalinorvar-exportervarexporterserializable-closuresymfony/yaml🏆 Победитель
Формат PHP (native serialize)✅❌❌❌❌❌❌❌CloudCastle
Формат JSON✅✅✅❌❌❌❌❌CloudCastle, symfony/serializer …
Формат XML✅✅✅❌❌❌❌❌CloudCastle, symfony/serializer …
Формат CSV✅✅❌❌❌❌❌❌CloudCastle, symfony/serializer
Формат YAML✅✅✅❌❌❌❌✅CloudCastle, symfony/serializer …
Формат NDJSON (построчный поток)✅❌❌❌❌❌❌❌CloudCastle
Формат igbinary✅❌❌❌❌❌❌❌CloudCastle
Формат MessagePack✅❌❌❌❌❌❌❌CloudCastle
Экспорт в исполняемый PHP-код✅❌❌❌✅✅❌❌CloudCastle, var-exporter …
Маппинг объект ↔ массив✅✅✅✅❌❌❌❌CloudCastle, symfony/serializer …
Типизированные коллекции без docblock-парсинга✅❌✅✅❌❌❌❌CloudCastle, jms/serializer …
Полиморфизм по карте дискриминатора✅✅✅✅❌❌❌❌CloudCastle, symfony/serializer …
Группы сериализации✅✅✅❌❌❌❌❌CloudCastle, symfony/serializer …
Версионирование схемы (since/until)✅❌✅❌❌❌❌❌CloudCastle, jms/serializer
Стратегии именования (snake/kebab/pascal)✅✅✅❌❌❌❌❌CloudCastle, symfony/serializer …
Маскирование персональных данных для логов✅❌❌❌❌❌❌❌CloudCastle
Белый список классов при десериализации✅❌❌❌❌❌❌❌CloudCastle
Лимит размера нагрузки✅❌❌❌❌❌❌❌CloudCastle
Лимит вложенности графа объектов✅✅❌❌❌❌❌❌CloudCastle, symfony/serializer
HMAC-подпись нагрузки✅❌❌❌❌❌✅❌CloudCastle, serializable-closure
Ротация ключей подписи без простоя✅❌❌❌❌❌❌❌CloudCastle
Шифрование нагрузки (XSalsa20-Poly1305)✅❌❌❌❌❌❌❌CloudCastle
Срок жизни нагрузки (TTL)✅❌❌❌❌❌❌❌CloudCastle
Прозрачное сжатие нагрузки✅❌❌❌❌❌❌❌CloudCastle
Сериализация замыканий✅❌❌❌❌❌✅❌CloudCastle, serializable-closure
Анонимные функции внутри произвольных структур✅❌❌❌❌❌❌❌CloudCastle
Сериализация объектов анонимных классов✅❌❌❌❌❌❌❌CloudCastle
Потоковая запись и чтение коллекций✅❌❌❌❌❌❌❌CloudCastle
Обнаружение циклических ссылок✅✅❌❌❌❌❌❌CloudCastle, symfony/serializer
Ноль обязательных зависимостей✅❌❌❌❌❌❌❌CloudCastle
Всего3010931121🏆 CloudCastle

2. Безопасность и корректность

СвойствоCloudCastlesymfony/serializerjms/serializervalinorvar-exportervarexporterserializable-closuresymfony/yaml🏆 Победитель
Объекты запрещены при десериализации по умолчанию✅✅✅✅✅✅❌✅CloudCastle, symfony/serializer …
Белый список классов вместо «доверяем нагрузке»✅✅✅✅❌❌❌❌CloudCastle, symfony/serializer …
Лимит размера нагрузки до разбора✅❌❌❌❌❌❌❌CloudCastle
Лимит вложенности графа✅✅❌❌❌❌❌❌CloudCastle, symfony/serializer
HMAC-подпись со сверкой за константное время✅❌❌❌❌❌❌❌CloudCastle
Ротация ключей подписи✅❌❌❌❌❌❌❌CloudCastle
Аутентифицированное шифрование нагрузки✅❌❌❌❌❌❌❌CloudCastle
Ограничение срока действия нагрузки✅❌❌❌❌❌❌❌CloudCastle
Запрет DTD при разборе XML (анти-XXE)✅❌❌❌❌❌❌❌CloudCastle
Лимит распаковки архива (анти-zip-бомба)✅❌❌❌❌❌❌❌CloudCastle
Маскирование персональных данных в логах✅❌❌❌❌❌❌❌CloudCastle
Обязательная подпись при сериализации кода✅❌❌❌❌❌✅❌CloudCastle, serializable-closure
Контрактные исключения вместо предупреждений✅✅✅✅❌❌❌✅CloudCastle, symfony/serializer …
Ноль транзитивных зависимостей в рантайме✅❌❌❌❌❌❌❌CloudCastle
Всего144331112🏆 CloudCastle

3. Качество кода

МетрикаCloudCastlesymfony/serializerjms/serializervalinorvar-exportervarexporterserializable-closuresymfony/yaml🏆 Победитель
Обязательных зависимостей в рантайме02421102🏆 CloudCastle
Файлов со строгой типизацией, %100010098.4010000🏆 CloudCastle
Строк кода57811193313999232972981123827513328без победителя
Строк кода на одну возможность1931193155577662981123813763328🏆 CloudCastle

4. Производительность

20 000 итераций, минимум из 3 прогонов, мс.

РешениеCloudCastlesymfony/serializerjms/serializervalinorvar-exportervarexporterserializable-closuresymfony/yamlserialize¹json¹igbinary¹msgpack¹var_export¹🏆 Победитель
Round-trip вложенной структуры56,983,9471,5—————47,373,333,645—🏆 CloudCastle
Маппинг объекта в массив и обратно287,1993,3—1 124,3—————————🏆 CloudCastle
Экспорт значения в исполняемый PHP-код165,7———421,4538,2——————71,2🏆 CloudCastle
Round-trip конфигурации в YAML968,1——————5 014,4—————🏆 CloudCastle
Round-trip замыкания2 939,3—————1 208,1——————🏆 serializable-closure

5. Потребление памяти

пик памяти самой библиотеки на 20 000 итераций (изолированный процесс, вычет базовой линии), KB.

РешениеCloudCastlesymfony/serializerjms/serializervalinorvar-exportervarexporterserializable-closuresymfony/yamlserialize¹json¹igbinary¹msgpack¹var_export¹🏆 Победитель
Round-trip вложенной структуры47291 051—————1111—🏆 symfony/serializer
Маппинг объекта в массив и обратно1871 026—1 283—————————🏆 CloudCastle
Экспорт значения в исполняемый PHP-код44———751 235——————1🏆 CloudCastle
Round-trip конфигурации в YAML87——————380—————🏆 CloudCastle
Round-trip замыкания5 054—————5 330——————🏆 CloudCastle

¹ Базовый уровень — нативные функции PHP и расширения без полноты решения: они показаны для контекста и не претендуют на победу среди библиотек.

Честно о плюсах и минусах

Сильные стороны

  • Функциональный суперсет: всё, что умеют сравниваемые библиотеки вместе взятые, плюс подпись, шифрование, TTL, сжатие, потоковый формат и маскирование персональных данных.
  • Быстрее аналогов во всех измеренных сценариях и заметно экономнее по памяти на маппинге объектов.
  • Безопасность заложена в поведение по умолчанию, а не в советы из документации.
  • Нет зависимостей: обновление пакета не тянет чужие уязвимости и конфликты версий.

Ограничения, о которых стоит знать

  • На простом round-trip массива нативные serialize() и igbinary быстрее: библиотека добавляет проверки, которых у них нет. Если данные заведомо доверенные и нужен максимум скорости — берите нативные функции.
  • По удерживаемой памяти на round-trip JSON symfony/serializer немного экономнее — осознанный компромисс в пользу функциональности и проверок.
  • YAML поддержан подмножеством спецификации (отображения, списки, скаляры, комментарии): якоря, теги и многодокументные потоки не разбираются.
  • Перенос анонимных функций и объектов восстанавливает код, но не привязку $this, не область видимости класса и не статические свойства; объявление должно быть единственным на строке исходного файла.
  • Экосистемных интеграций (бандлы, провайдеры фреймворков) пока нет — подключение ручное.

Где применять

ЗадачаРекомендация
Очереди и фоновые задачиSerializer::signed() поверх php() — подделанное сообщение отбрасывается до разбора
Cookie и клиентские токеныsigned() + expiring() + compressed() — компактно, tamper-proof, с TTL
Межсервисный обменjson() или msgpack() для языковой нейтральности, поверх — подпись
Персональные и платёжные данныеencrypted() для хранения, Context::forLogging() для логов
Конфигурации приложенияyaml() для правки человеком, exporter() для opcache-кэша
Выгрузки и отчётыcsv() с типизированными заголовками, ndjson() для больших наборов
Коллекции в миллионы записейndjson()->writeTo() и readFrom() — постоянное потребление памяти
API с версионированием контрактаmapper() с атрибутами #[Since], #[Until] и группами
Недоверенный ввод из внешнего мираphp() без белого списка либо json() — лимиты уже включены
Правила и обработчики в конфигурацииdynamic() — замыкания и анонимные объекты переносятся с подписью

Когда пакет не нужен: одноразовый json_encode() внутри одного процесса, работа исключительно с доверенными данными без требований к безопасности или уже настроенный symfony/serializer в Symfony-проекте, где единообразие с фреймворком важнее перечисленных возможностей.

Разработка

composer install
composer check        # линтеры + статический анализ + тесты
composer fix          # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci           # полный CI-пайплайн локально
composer docs:build   # пересборка сравнительных таблиц из реальных прогонов

Полный список команд с описаниями: composer run-script --list.

Документация

Лицензия

MIT © CloudCastle (alex-4-17@yandex.ru)

🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano