Iblock 26.100.0: файловые поля в БП только по ID, REST v3 для элементов
Обновление безопасности
Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.
Iblock 26.100.0 (сборка от 14 сентября 2026) закрывает две дыры: подстановку путей, URL и массивов файлов в файловые поля через документ бизнес-процесса и обход прав при inline-редактировании цен в админке. Первая правка сломает шаблоны БП и свои активити, которые пишут в поле «Файл» ссылку или путь. Ещё в релизе первый REST v3-контроллер модуля и шаблоны каталога, переделанные под клавиатуру и экранные дикторы.
Новое
Читайте элементы через REST v3
Контроллер Bitrix\Iblock\Infrastructure\Rest\Controller\Element даёт два метода, iblock.element.get и iblock.element.list. Оба только читают и работают с инфоблоками, у которых REST_ON = Y, на остальные отвечают ошибкой «Restricted iblock». По коду сервиса нужен ещё символьный код API. Без API_CODE ORM-сущность инфоблока не соберётся, и придёт Unable to compile iblock entity.
Поля отдаются по белому списку: id, iblockId, name, iblockSectionId и properties, где свойства лежат по коду со значениями id, value, description. Фильтровать можно по всем четырём скалярным полям, сортировать по всем, кроме iblockId. В list фильтр по iblockId обязателен, в get инфоблок передаётся параметром iblock. Раздел 0 приходит как null, лимит по умолчанию 50.
curl -s -X POST "https://portal.example.ru/rest/api/1/<secret>/iblock.element.list" \
-H "Content-Type: application/json" \
-d '{
"filter": [["iblockId", 12], ["iblockSectionId", 34]],
"select": ["id", "name", "properties"],
"order": {"name": "ASC"},
"pagination": {"limit": 20}
}'
Для одного элемента вызовите iblock.element.get с телом {"iblock": 12, "id": 345}. REST v3 и более строгие права приехали и в catalog, разбор в catalog 26.500.0.
Сохраняйте inline-цены публичной командой
Bitrix\Iblock\Public\Command\Catalog\SaveInlinePricesCommand сохраняет цены и закупочные цены так же, как inline-редактирование списка в админке. Каждый элемент пишется в своей транзакции. Ошибки приходят с кодами NO_BASE_PRICE, SAVE_FAILED и CATALOG_NOT_INSTALLED, ID элемента лежит в customData['ELEMENT_ID']. Права команда не проверяет, это делает вызывающий код. Какие элементы можно править из списка, подскажет Bitrix\Iblock\Public\Provider\Catalog\InlineEditTargetProvider. Его getEditableIblockIds() возвращает инфоблок списка и SKU-инфоблок его каталога, getProductIdsWithOffers() возвращает товары с активными ТП.
Каталог работает с клавиатуры и с экранным диктором
Под доступность переделаны системные шаблоны catalog.element, catalog.item, catalog.section, catalog.smart.filter и iblock.vote (bootstrap_v4), catalog.element, catalog.item, catalog.section и catalog.section.list (store_v3, store_v3_menu), catalog.compare.result и catalog.compare.list (.default). Для покупателя изменилось:
- карточка в списке раскрывается и при фокусе с клавиатуры, раскрытой бывает только одна;
- кнопки количества, стрелки галереи, миниатюры, кнопки покупки и заголовки свойств в фильтре стали
<button>, до них доходит Tab; - у полей «от/до» в фильтре появились скрытые подписи для экранного диктора;
- в таблице сравнения пустая ячейка озвучивается как «Нет значения», а строка с названиями товаров видна и в режиме «только различающиеся».
Клавиатуру и озвучку даёт расширение ui.a11y (BX.UI.Accessibility.FocusZone, FocusTrap, LiveAnnouncer, FocusNavigator). Без него страница работает, пропадают только эти функции. Шаблоны подключают расширение в component_epilog.php, потому что при попадании в кеш тело шаблона не выполняется, а в композите оно лежит в динамической зоне. В своих шаблонах подключайте его там же.
Что сломается
Передавайте в файловые поля БП только ID
CIBlockDocument::UpdateDocument() и CreateDocument() теперь принимают в файловые поля только ID из b_file, числом или строкой из цифр. Путь на сервере и URL отбрасываются молча. В UpdateDocument последствия хуже. Если ни одно значение не прошло проверку, поле получает del => Y, и текущий файл элемента удаляется. Эта ветка была и раньше, но теперь в неё попадают пути и URL.
Ключ, в значении которого на любой глубине есть массив с tmp_name или old_file, теперь выбрасывается целиком, необъявленный PROPERTY_VALUES тоже. Ключ PROPERTY_<CODE|ID> активного файлового свойства обрабатывается как файл, какой бы тип ни стоял в полях документа.
По комментариям в коде, строку CFile::MakeFileArray() прочитал бы как локальный путь или скачал бы по URL, а CFile::SaveFile() копирует tmp_name и удаляет файл из old_file. Через поля документа и ключ PROPERTY_VALUES можно было прицепить к элементу любой файл с сервера, заставить портал скачать URL или удалить чужой файл.
Сломаются шаблоны БП, которые пишут в поле «Файл» элемента ссылку или путь строкой, свои активити и код, который так же вызывает эти методы. Сохраните файл сами и передайте ID. Документ запишет свою копию файла новой записью в b_file, поэтому исходную запись после вызова удалите. Для множественного свойства передайте массив ID. Файлы, которых в нём нет, SetPropertyValuesEx() удалит, так что список заменяет текущие файлы целиком.
<?php
declare(strict_types=1);
namespace Vendor\Bizproc;
use Bitrix\Main\SystemException;
final class WorkflowFileAttacher
{
public function __construct(private readonly \CBPDocumentService $documentService)
{
}
/** С iblock 26.100.0 документ принимает в файловые поля только ID из b_file. */
public function attach(array $documentId, string $propertyCode, string $source): void
{
// $source берите из доверенного места: строка из формы даст ту же дыру, что закрыли в ядре
$file = \CFile::MakeFileArray($source);
if (!is_array($file) || empty($file['tmp_name'])) {
throw new SystemException("Файл не получен: {$source}");
}
$fileId = (int)\CFile::SaveFile($file, 'iblock');
if ($fileId <= 0) {
throw new SystemException("Файл не сохранён: {$source}");
}
try {
$this->documentService->UpdateDocument($documentId, ['PROPERTY_' . $propertyCode => $fileId]);
} finally {
// документ хранит свою копию файла, исходная запись в b_file не нужна
\CFile::Delete($fileId);
}
}
}
В активити сервис берётся из $this->workflow->GetService('DocumentService'), ID документа из $this->GetDocumentId().
Проверьте свой CSS и JS поверх bootstrap_v4 и store_v3
Это касается тех, кто вешал стили и скрипты на системные шаблоны каталога, не копируя их в шаблон сайта. Скопированные шаблоны обновление не трогает.
- У
JCCatalogItemBootstrapV4удаленыhoverOn,hoverOff,onFocus,onBlurиcaptureMousePosition. Наведение теперь обрабатываютonPointerEnter,onPointerMoveиonPointerLeave, фокус внутри карточки (focusin/focusoutна самой карточке) обрабатывают новыеonCardFocusInиonCardFocusOut. Прямой замены уonFocus,onBlurиcaptureMousePositionнет, обработчики focus/blur с поля количества сняты. JCSmartFilter.prototype.selectDropDownItemудалён изbootstrap_v4(в.defaultостался). Выбор в выпадающем списке идёт черезselectDropDownValueиcloseDropDownPopup.- В разметке
spanиdivинтерактивных элементов сталиbutton, ссылка покупкиa.product-item-detail-buy-buttonтоже. Списки свойств и диапазонов ценul.product-item-detail-properties > liв карточке товара сталиdl > divсdt/dd, точки.product-item-detail-properties-dotsубраны.a.product-item-image-wrapperв карточке списка сталdiv, а ссылка ушла внутрь, вa.product-item-image-link. У меток и кольца скидки убранtitle. В таблице сравнения появился<thead>, а вcatalog.compare.resultonclickвыбора свойств переехал соspanна чекбокс. - В
store_v3миниатюры галереиdiv.product-detail-slider-controls-imageиdiv.catalog-section-item-slider-controls-imageсталиbutton.
Автотесты по таким селекторам тоже упадут. В шаблонах появилось около сотни data-testid, к ним тесты и стоит привязать.
Проверьте свои скрипты inline-цен
В iblock_element_admin.php и iblock_list_admin.php право на цену проверялось по инфоблоку списка, а не по инфоблоку элемента. CATALOG_PRICE_ID из POST уходил в CPrice::Update() и CPrice::Delete() без проверки, чья это цена. Теперь права проверяются по инфоблоку цели, ID цены другого товара или другого типа цены отбрасывается, а строки не из инфоблока списка и не из SKU-инфоблока его каталога пропускаются. Цены разбираются из $_POST['FIELDS'][<row>][CATALOG_GROUP_<N>_custom], прямые $_POST['CATALOG_PRICE'] и CATALOG_CURRENCY больше не читаются. При SKU и новой карточке (USE_NEW_CARD) закупочная цена из строки товара сохраняется в выбранное торговое предложение.
В тех же списках поменялись права документооборота. «Изменить» появилось у опубликованного элемента для тех, кто может перевести его в другой статус, а активация, транслитерация кода и сброс счётчика остались только при праве на статус от 2.
Мелочи и находки
- Формы элемента в админке и
iblock.element.add.formпередают в БПBitrix\Bizproc\Starter\Enum\ManualStartSurfaceбез проверкиclass_exists. В эталоне это перечисление появилось в bizproc 26.1400.0, так что bizproc обновляйте не позже iblock. catalog.smart.filterпри переходе наUri::addParams()потерял опциюskip_empty. ВFILTER_URLиFILTER_AJAX_URLтеперь могут оставаться пустые параметры вродеbxajaxid=. Если разбираете эти ссылки в своём коде, проверьте.- В
catalog.section/bootstrap_v4у варианта раскладки 3 (четыре карточки в ряд) классcol-6 col-md-3сменился наcol-6 col-lg-3. На ширине 768–991 px в ряду теперь две карточки вместо четырёх. - Прошлая версия, 26.0.100, собрана за четыре дня до этой и запретила восстанавливать объекты из
USER_TYPE_SETTINGS_LIST, разбор в iblock 26.0.100.
Устаревшие и удалённые API в этой версии
| Символ | Статус | Чем заменять |
|---|---|---|
JCCatalogItemBootstrapV4.prototype.hoverOn()
|
Удалено |
JCCatalogItemBootstrapV4.prototype.onPointerEnter()
|
JCCatalogItemBootstrapV4.prototype.hoverOff()
|
Удалено |
JCCatalogItemBootstrapV4.prototype.onPointerLeave()
|
JCCatalogItemBootstrapV4.prototype.captureMousePosition()
|
Удалено | — |
JCCatalogItemBootstrapV4.prototype.onFocus()
|
Удалено | — |
JCCatalogItemBootstrapV4.prototype.onBlur()
|
Удалено | — |
JCSmartFilter.prototype.selectDropDownItem()
|
Удалено |
JCSmartFilter.prototype.selectDropDownValue()
|