Iblock 26.0.100: ORM-поле USER_TYPE_SETTINGS_LIST больше не восстанавливает объекты
Обновление безопасности
Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.
Сборка от 10 сентября 2026, содержательная правка в ней одна. Bitrix\Iblock\PropertyTable теперь десериализует поле USER_TYPE_SETTINGS_LIST (колонка USER_TYPE_SETTINGS) с запретом классов. Если вы пишете свои пользовательские типы свойств инфоблока и храните в настройках обычные массивы, для вас ничего не изменится. Если хранили там объект, ORM теперь вернёт __PHP_Incomplete_Class. Миграций БД нет, deprecated нет, публичные сигнатуры не менялись.
Проверьте, что лежит в USER_TYPE_SETTINGS
Поле USER_TYPE_SETTINGS_LIST (колонка USER_TYPE_SETTINGS в b_iblock_property) раньше было штатным ArrayField, а тот в decodePhp() зовёт unserialize($value) без ограничений. Теперь поле описано анонимным наследником ArrayField прямо в getMap(), и декодер у него свой:
return unserialize($value, ['allowed_classes' => false]);
Правка касается чтения USER_TYPE_SETTINGS_LIST: явного select, select * и fetchObject(). Сериализованный объект в этом поле больше не восстановится, вместо экземпляра своего класса вы получите __PHP_Incomplete_Class. Отдельное поле USER_TYPE_SETTINGS (TextField на ту же колонку) ORM не десериализует и отдаёт строкой, как раньше. Там, где старое API само разбирает колонку (CIBlockPropertyResult, CIBlockElement), unserialize и до релиза вызывался с allowed_classes => false, так что объект приходил как __PHP_Incomplete_Class (по коду iblock 26.0.0 в эталоне).
Пользовательский тип заметит изменение там, где ядро копирует USER_TYPE_SETTINGS_LIST в USER_TYPE_SETTINGS перед вызовом типа. По коду в эталоне это, например, списки элементов в админке (iblock_element_admin.php:359, iblock_list_admin.php:343), грид (usertypepropertyfieldassembler.php:43) и фильтр элементов (elementfilterfields.php:495).
Допустим, кто-то решил, что хранить настройки типа в виде DTO удобнее, чем массивом:
<?php declare(strict_types=1);
namespace Vendor\Catalog\Property;
final class RatingSettings
{
public function __construct(
public readonly int $maxStars = 5,
public readonly bool $allowHalf = false,
) {}
}
// и в настройки свойства уехал объект:
// USER_TYPE_SETTINGS = serialize(['config' => new RatingSettings(10, true)])
После обновления чтение выглядит так:
<?php declare(strict_types=1);
use Bitrix\Main\Loader;
use Bitrix\Iblock\PropertyTable;
Loader::requireModule('iblock');
$property = PropertyTable::query()
->setSelect(['ID', 'CODE', 'USER_TYPE_SETTINGS_LIST'])
->where('CODE', 'RATING')
->fetch();
$config = $property['USER_TYPE_SETTINGS_LIST']['config'];
var_dump($config instanceof \Vendor\Catalog\Property\RatingSettings); // false
var_dump($config::class); // __PHP_Incomplete_Class
$config->maxStars; // до свойств неполного объекта не достучаться
На стороне БД ничего не поменялось, в колонке лежит та же строка.
Храните настройки массивом скаляров
Обычные настройки пользовательских типов, то есть массивы со строками, числами и флагами, читаются как раньше. Если объект в коде всё-таки нужен, собирайте его из массива уже после чтения:
<?php declare(strict_types=1);
use Vendor\Catalog\Property\RatingSettings;
// в USER_TYPE_SETTINGS лежит только это:
$settings = [
'MAX_STARS' => 10,
'ALLOW_HALF' => 'Y',
];
// $property получен из PropertyTable, как в примере выше,
// а DTO собираем сами, на своей стороне:
$stored = $property['USER_TYPE_SETTINGS_LIST'] ?? [];
$config = new RatingSettings(
maxStars: (int)($stored['MAX_STARS'] ?? 5),
allowHalf: ($stored['ALLOW_HALF'] ?? 'N') === 'Y',
);
Так настройки не зависят от того, существует ли класс, переименовали ли его и как именно ядро вызывает unserialize.
Мелочи и находки
- Мотив в диффе не назван, комментария в коде нет. По самой правке (
allowed_classes => false) это похоже на харднинг против PHP Object Injection через содержимоеb_iblock_property.USER_TYPE_SETTINGS. ArrayFieldв main не трогали, новой опции конфигурации у поля не появилось.->configureSerializationPhp()остался на месте, переопределён только декодер. ДругихArrayFieldс PHP-сериализацией в этом диффе нет.- Метода
PropertyTable::decodePhp()из паспорта API не существует. Генератор приписалPropertyTableметод анонимного класса поля изgetMap(), нового публичного API в релизе нет. - В остальном только версия:
26.0.0→26.0.100вinstall/version.php, заодно убрали пустую строку после<?phpи висячую запятую в массиве.
Что делать
- Поищите в своих пользовательских типах свойств места, где в
USER_TYPE_SETTINGSпопадает что-то кроме массивов и скаляров. - Если нашли объект, пересохраните такие свойства с массивом скаляров, а DTO собирайте в коде после чтения.
- Если в настройках у вас и так одни массивы, для вашего кода поведение прежнее.