Main 26.800.0: закрыт SSRF через ftp://, а translit и выбор SMTP-отправителя работают иначе
Обновление безопасности
Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.
Main 26.800.0 закрывает SSRF в CFile::MakeFileArray() через ссылки ftp:// и в RSS-гаджете, а заодно чистит ввод при инлайн-редактировании в CAdminUiList и в menu_edit.php. Сильнее по проектам ударят изменения поведения: CUtil::translit() оставляет на конце _, почта по-другому выбирает SMTP-отправителя и его лимит, а у DDL-билдеров миграций переименовали параметр. Дифф большой, 850 файлов (+30852/−19139), но примерно половина приходится на PNG, переведённые в WebP, и на JS, пересобранный после переписывания main.sidepanel и main.popup на TypeScript.
Что сломается
Уберите хвостовой _ из символьных кодов
С настройками по умолчанию (delete_repeat_replace = true) CUtil::translit() раньше молча выбрасывал последний символ строки, если того нет в таблице транслитерации. Теперь последний символ заменяется на replace_other, как и все остальные, если перед ним не стоит та же замена: из условия убрали $i != $len - 1. На обычных названиях это выглядит так:
<?php declare(strict_types=1);
\CUtil::translit('Скидка 10%', 'ru'); // skidka_10_ (было skidka_10)
\CUtil::translit('Что нового?', 'ru'); // chto_novogo_ (было chto_novogo)
\CUtil::translit('Модуль (beta)', 'ru'); // modul_beta_ (было modul_beta)
Задето всё, что строит символьные коды и имена через CUtil::translit. Если хвост вам не нужен, срежьте его сами:
<?php declare(strict_types=1);
$code = rtrim(\CUtil::translit($name, 'ru'), '_');
Там же переделали CFile::transformName(). Транслитерацию вынесли в новый protected static CFile::transliterate(string $name), и работает она только для физического имени файла и только при save_original_file_name = Y. ORIGINAL_NAME (первый элемент результата) больше не транслитерируется совсем, даже с translit_original_file_name = Y. Кто включал эту опцию ради латинского ORIGINAL_NAME, теперь получит имя в том виде, в каком файл загрузили. В safe_chars вместо одной точки стоит ._-(), так что дефисы и скобки в физическом имени сохраняются.
Проверьте переводы из translation_repository
Loc::loadLanguageFile() и loadCustomMessages() больше не перекодируют языковые файлы: вызовы Translation::getEncodings() и Encoding::convertEncoding() из них удалены. Раньше перекодировка работала, только если в .settings.php в секции translation включён convert_encoding и lang-файл лежит в translation_repository или developer_repository. Если у вас так и файлы там не в UTF-8, фразы теперь попадут в $MESS байт в байт и выведутся битыми символами. Файлы из /local/ и /bitrix/modules/ не перекодировались и раньше, для них ничего не меняется.
Поменялась и работа с константой BX_MESS_CODE. Раньше getMessage() при ней сразу возвращал код фразы. Теперь код подставляется вместо значения при загрузке lang-файла, поэтому код вместо текста вы увидите только у фраз, которые реально загружены из файлов.
Проверьте, через какой SMTP уходят письма
Больше всего изменений касается порталов, где один адрес подключён отправителем несколько раз, например разными сотрудниками.
Sender::getCustomSmtp($email) без identity теперь ищет отправителя через Sender\IdentityResolver::resolve(). Раньше бралась самая новая подтверждённая запись с SMTP (ORDER BY ID DESC). Теперь записи идут по возрастанию ID, и из нескольких совпадений выбирается первая публичная (IS_PUBLIC), а если публичной нет, самая старая. Если у дублей разные SMTP-настройки, после обновления письма могут пойти через другой сервер. Каждый неоднозначный выбор пишется в журнал событий с типом MAIL_SENDER_AMBIGUOUS, не чаще раза в сутки на адрес. Поищите эти записи после обновления, по ним видно, какие адреса стоит развести.
С лимитами тоже по-новому:
Sender::getEmailLimit($email)без identity возвращает минимальный положительный лимит среди подтверждённых записей адреса. Раньше брался лимит самой новой подтверждённой записи, у которой он вообще задан, даже если это 0. С identity берётся лимит только найденной записи.Sender::updateSender()больше не раздаётOPTIONS.smtp.limitвсем записям адреса черезsetEmailLimit(), а из контроллераBitrix\Main\Controller\Mail\SenderудалёнprepareLimits(). Формаmain.mail.confirmпишет лимит только в редактируемую запись через новыйSender::setSenderLimit()иremoveEmailLimit()больше не вызывает.
Обработчик Sender::applyCustomSmtp() на main:OnBeforePhpMail стал строже. Если в Mail\Context задан identity, а адрес в From не совпадает с адресом найденного отправителя, он возвращает EventResult::ERROR с кодом MAIL_SENDER_ADDRESS_MISMATCH, и bxmail() отдаёт false. Проверка срабатывает только там, где identity уже передают. При Context::setAutomaticCustomSmtpEnabled(false) кастомный SMTP вообще не подбирается.
В Mail\Internal\SenderTable у поля EMAIL появился save-модификатор Address::normalizeEmail() (mb_strtolower(trim())). Адрес приводится к нижнему регистру на любой записи, включая addMulti и updateMulti. Ещё переопределены update() и delete(): каждый вызов делает дополнительный SELECT текущей строки и сбрасывает кеши. Массовое обновление отправителей в цикле получит по лишнему запросу на строку.
Действие main.mail.sender.getAvailableSenders теперь отдаёт UserSenderDataProvider::getUserAvailableSenderIdentities() вместо Sender::prepareUserMailboxes(). Дедупликации там нет, и записи с одинаковым отображаемым значением остаются в списке. Если вы строите по нему свой выпадающий список, готовьтесь к одинаковым строкам.
Прошлая правка почты в main вышла в 26.750.0, там чинили плейсхолдеры с точкой в шаблонах.
Замените ссылки на удалённые PNG
Часть картинок удалили, на их место пришли WebP:
/bitrix/panel/main/images/icons-sprite-14.png,adm-security-banner-warning-icon.png,composite/composite_home.png;/bitrix/js/main/core/images/panel/top-panel-sprite-2.png;/bitrix/js/main/phonenumber/flag/sprite-{16,24,32}.png;- картинки чек-листа и ассеты
imageeditor.
Своя CSS со ссылками на эти пути сломается. Найти их можно так:
grep -rnE 'icons-sprite-14\.png|adm-security-banner-warning-icon\.png|composite_home\.png|top-panel-sprite-2\.png|phonenumber/flag/sprite-' local/
Переименуйте mysqlIndexName и поправьте наследников DDL-билдеров
В Bitrix\Main\DB\Ddl\Builder\IndexesTrait у addIndex(), addUniqueIndex() и addFulltextIndex() параметр $mysqlIndexName переименован в $indexName. Позиционные вызовы вроде $table->addIndex('ix_vendor_log_user', ['USER_ID']) работают как раньше (на PostgreSQL имя в миграциях затем нормализует IndexNameProcessor, о нём ниже), а вызов с именованным аргументом mysqlIndexName: упадёт с Error про неизвестный параметр.
Во всех DDL-билдерах и колонках (AlterTableBuilder, IndexesTrait, AbstractColumn, AbstractIntColumn и других) возвращаемый тип self заменили на static. Наследник, который переопределяет такой метод с : self, станет несовместим с родителем, и PHP откажется загружать класс.
По мелочи в том же слое:
AlterTableBuilder:dropIndexNameResolverполучает второй аргумент$hintName. Если резолвер вернулnull, drop пропускается, а раньше в этом случае бралось имя-подсказка.PgsqlRenderer::renderAlterColumnLines()получил параметр?ColumnState $state = null, а индексы в PostgreSQL теперь создаются под переданным именем.Migration\Tools\SpyTable::__construct()получил обязательный параметрIndexNameProcessor $indexNameProcessor.
Изменилось и поведение Migration\Table. dropIndex() без списка колонок в dev-режиме бросает исключение 1104, иначе операция пропускается с записью в лог. modifyColumn по отсутствующей колонке пропускается. Все операции идут в режиме master-only, SQL выполняется через $connection->queryExecute(), а при установке и удалении модуля ошибка превращается в исключение 1199.
CModule::installMigrations() и uninstallMigrations() теперь ловят Migration\Exception и возвращают его ошибкой в Result. Если ваш установщик оборачивал их в try/catch, catch больше не сработает: проверяйте isSuccess().
Не разбирайте ключи ORM-коллекции
Bitrix\Main\ORM\Objectify\Collection::sysSerializePrimaryKey() сменил формат внутренних ключей _objects. Одиночный ключ теперь проходит через json_encode(), составной превращается в JSON-объект с именами полей (раньше был JSON-список значений). Эти ключи видны снаружи в foreach, если первичный ключ строковый или составной:
<?php declare(strict_types=1);
foreach ($collection as $key => $object) {
// строковый ключ 'ru': было ru, стало "ru" (с кавычками)
// составной ключ ID = 1, LANG_ID = 'ru': было [1,"ru"], стало {"ID":1,"LANG_ID":"ru"}
$primary = $object->primary; // так надёжнее, чем разбирать $key
}
С целочисленным ID ключи прежние.
Пройдитесь по мелким контрактам
CUserCounterPage::setNewEvent()удалён вместе с защищённымиgetMinMax(),getUserIdOption()иsetUserIdOption(), его вызов убран изCAllUserCounter.checkSendCounter()больше не вызывается изCMain::RunFinalActionsInternal(): он зарегистрирован как background job вApplication::initializeBackgroundJobs()и работает без обёртки$DB->StartUsingMasterOnly(), а проверкаCUserCounter::CheckLiveMode()переехала внутрь метода.- Константы
START_EXEC_EVENTS_1иSTART_EXEC_EVENTS_2теперь float (microtime(true)), а не строка"usec sec".START_EXEC_EVENTS_2определяется после обработчиковOnAfterEpilog, а не до них. Если вы считаете по ним время, уберите разбор строки. - JS
BX.Main.PopupManager:handlePopupDestroy,handlePopupShowиhandlePopupCloseстали приватными (#),handleOnAfterInitстал стрелочной функцией-свойством. Снаружи первые три больше не вызвать. - В
.settings.phpмодуля секцияrestсменилаdefaultNamespaceна\Bitrix\Main\Infrastructure\Rest\Controller, а прежний\Bitrix\Main\Rest\V3\Controllerперенесён вnamespaces. InitFilterEx()сначала берёт значение фильтра из глобальной переменной$$nameи только потом из$_REQUEST. На старой админской странице глобальная переменная с именем поля фильтра перебьёт то, что пришло в запросе.
Какие дыры закрыли
CFile::MakeFileArray() для путей ftp:// и ftps:// теперь резолвит хост через Web\IpAddress::createByUri(), отклоняет приватные адреса и подставляет в URL полученный IP. До этого от SSRF был защищён только http(s) через HttpClient::setPrivateIp(false). Гаджет rssreader создаёт HttpClient с privateIp => false, так что URL ленты тоже больше не уведёт запрос на внутренний адрес.
Остальное касается ввода:
CAdminUiListпри инлайн-редактировании кастомных полей с именами видаa[b][c]отбрасывает элементы, у которых сегмент ключа начинается с~или=(в комментарии ядра это «маркеры сырого SQL»). Запись идёт только вFIELDS[$id]текущей строки, а сегментыFIELDSи id, присланные клиентом, игнорируются.public/menu_edit.phpпроверяетcheck_bitrix_sessid()в самом начале обработки POST. Параметры пункта меню[2],[3]и[4], включая условие показа, больше не десериализуются из POST-поляadditional_params_Nи берутся из существующего файла меню.main.mail.confirm/ajax.phpприводит ID отправителя к int до проверки владельца. ПрежнийsetEmailLimit($email, …)менял лимит у всех подтверждённых записей с тем же адресом, в том числе у чужих, теперь лимит пишется только в редактируемую запись.Mail\Trackingпринимает URL от обработчика нового событияOnMailEventMailClickRedirectтолько при том же origin (схема, хост, порт) и учитывает протокол-относительные формы//,/\и\\.
Deprecated
CHTTP::Download() помечен на замену Bitrix\Main\Web\HttpClient, CHTTP::PrepareData() на http_build_query():
<?php declare(strict_types=1);
use Bitrix\Main\Application;
use Bitrix\Main\Web\HttpClient;
// было: (new \CHTTP())->Download($url, $path);
$http = new HttpClient(['socketTimeout' => 10, 'streamTimeout' => 30, 'privateIp' => false]);
$saved = $http->download($url, Application::getDocumentRoot() . '/upload/tmp/price.xml');
// было: CHTTP::PrepareData($data);
$query = http_build_query($data);
В JS у PopupManager на выпил пошли _popups и _currentPopup, вместо них getPopups() и getCurrentPopup(). Остальные строки в списке deprecated (PopupWindow, PopupMenuWindow, PopupMenuItem, кнопки в пользу BX.UI.Button, SliderEvent.getSliderPage(), SliderManager.getLastOpenPage() и getCurrentPage()) старые. Пометки стояли и в прежних .js, при переходе на TypeScript их перенесли в main.popup.bundle.d.ts и side-panel.bundle.d.ts.
Новое
Подмените содержимое файла, не меняя ID
Bitrix\Main\File\ContentReplacer::replace(int $fileId, int $replacementId, ?int $expectedReplacementId, string $owner): Result меняет содержимое, которое отдаётся по ID файла, и оставляет сам ID прежним. Инфоблоки, UF и HL-блоки продолжают ссылаться на $fileId. Связь лежит в существующей таблице b_file_version (ORIGINAL_ID хранит стабильный ID, VERSION_ID текущую замену), и CFile::GetByID() выбирает строку версии с ORDER BY ID DESC LIMIT 1.
Перед вызовом учтите:
- замену сохраняете заранее, например через
CFile::SaveFile(), и её ID должен быть больше$fileId; $expectedReplacementIdработает как оптимистичная блокировка:nullпри первом назначении, дальше ID текущей замены, при расхождении придётFILE_REPLACEMENT_CONFLICT;$owner— идентификатор вашего сервиса,[a-zA-Z0-9_.-]{1,100}, и проверкой прав он не служит. Связь с чужимversionOwnerметод не трогает и тоже возвращаетFILE_REPLACEMENT_CONFLICT;- блокировка
$connection->lock('b_file', 0)берётся без ожидания, занято —FILE_REPLACEMENT_LOCKED. Работа идёт вuseMasterOnly(true), и докблок требует вызывать метод вне внешней транзакции; - прежняя замена удаляется через
CFile::Delete(), исходный$fileIdне удаляется никогда. Если процесс упал между шагами, следующийreplace()сначала дочистит висящийobsoleteFileId; - цепочки запрещены (
isValidGraph()), все участвующие ID должны образовывать независимые пары один-к-одному.
<?php declare(strict_types=1);
use Bitrix\Main\File\ContentReplacer;
$replacementId = (int)\CFile::SaveFile($uploadedFile, 'vendor.pricelist');
$result = (new ContentReplacer())->replace(
fileId: $priceListFileId,
replacementId: $replacementId,
expectedReplacementId: $lastReplacementId, // null при первой замене
owner: 'vendor.pricelist',
);
if ($result->isSuccess()) {
$lastReplacementId = $replacementId; // сохраните у себя для следующего вызова
} else {
$code = $result->getErrors()[0]->getCode(); // FILE_REPLACEMENT_CONFLICT, _LOCKED, _INVALID, _WRITE_FAILED
}
Повторный вызов с той же заменой вернёт успех с changed = false в getData(). Для тестов и переопределения открыты protected updateReplacement() и deleteObsoleteFile().
Отправьте письмо от конкретного ящика и узнайте причину отказа
Bitrix\Main\Mail\Sender\Identity — иммутабельная ссылка на отправителя, без адреса и без запросов к БД. Создаётся через Identity::fromMailbox(int $mailboxParentId, string $mailboxModuleId = 'mail'), fromSender(int $senderId) или fromMailboxAndSender(...). CEvent::SendImmediate(), Mail\Event::sendImmediate() и handleEvent() получили параметры ?Identity $senderIdentity и ?Mail\Context $context, так что отправителя можно задать явно: \CEvent::SendImmediate('SALE_NEW_ORDER', 's1', $fields, senderIdentity: Identity::fromMailbox($mailboxId)). Отложенная очередь CEvent::Send() не сохраняет ни identity, ни context.
Mail::sendResult(array $mailParams): Result отправляет письмо и возвращает причину отказа: MAIL_SEND_CANCELED, MAIL_SEND_NOT_ALLOWED, MAIL_SEND_FAILED или ошибку из контекста вроде MAIL_SENDER_ADDRESS_MISMATCH. Mail::send() теперь вызывает его внутри.
<?php declare(strict_types=1);
use Bitrix\Main\Mail\Context;
use Bitrix\Main\Mail\Mail;
use Bitrix\Main\Mail\Sender\Identity;
$context = (new Context())->setSenderIdentity(Identity::fromMailbox($mailboxId));
$result = Mail::sendResult([
'TO' => $clientEmail,
'SUBJECT' => 'Счёт готов',
'BODY' => 'Счёт №123 можно оплатить до пятницы.',
'HEADER' => ['From' => 'sales@example.com'],
'CHARSET' => 'UTF-8',
'CONTENT_TYPE' => 'text',
'CONTEXT' => $context,
]);
foreach ($result->getErrors() as $error) {
// MAIL_SENDER_ADDRESS_MISMATCH: From не совпадает с адресом ящика
$logger->warning($error->getCode() . ': ' . $error->getMessage());
}
Свой обработчик OnBeforeMailSend может отменить отправку своей ошибкой: вернуть EventResult::ERROR с параметром ['error' => Error], и она дойдёт до вызывающего кода через sendResult().
Ещё по почте:
Mail\Context:setSenderIdentity(),setAutomaticCustomSmtpEnabled(?bool),setSendingError(?Error)и парные геттеры;Mail\Address::normalizeEmail(?string)— единая каноническая форма адреса,Sender\AddressFilter::applyEmails(Query $query, array $emails)вешает на запрос нормализованный фильтр (пустой список превращается в1 = 0);IdentityResolver::resolveForOwner(int $ownerId, string $email)ищет запись конкретного владельца, уSenderпоявилисьresolveSenderId(),resolveIdentityForOwner(),setSenderLimit(),clearSenderCache(),clearIdentitySenderCache();UserSenderDataProvider::getUserAvailableSenders()получил параметрbool $preserveIdentities = false;- событие
main:OnMailEventMailClickRedirectвызывается перед редиректом по трекинговой ссылке. Обработчик может вернуть['url' => ...], но новый URL примут только с тем же origin. Модуль sender уже вешает на него свойExternalUrlSanitizer.
Подсветите коды фраз прямо на странице
Loc::setMessageDecorator(?callable $decorator) ставит callback вида ($code, $raw, $s, $sourceFile, $language), который вызывается на каждый getMessage() до подстановки $replace. Loc::getMessageSourceFile(string $code, ?string $language = null) возвращает lang-файл фразы, но путь запоминается только для файлов, загруженных после установки декоратора. Поэтому ставить его надо рано, в init.php, иначе вместо пути получите null.
<?php declare(strict_types=1);
use Bitrix\Main\Config\Configuration;
use Bitrix\Main\Context;
use Bitrix\Main\Localization\Loc;
// local/php_interface/init.php: подсветка только на стенде с debug = true
$debug = Configuration::getValue('exception_handling')['debug'] ?? false;
if ($debug && Context::getCurrent()->getRequest()->getQuery('lang_debug') === 'Y') {
Loc::setMessageDecorator(
static fn ($code, ?string $raw, ?string $s, ?string $file, $lang): ?string
=> $s === null ? null : sprintf('%s [%s @ %s]', $s, $code, $file ?? '?'),
);
}
Катите миграции модуля на отдельное подключение
CModule::configureMigrationContext(Migration\Context $context) — protected-хук установщика, который вызывается перед прогоном install/migrations. Вместе с Migration\Context::setConnection() он отправляет таблицы модуля из tables.php на отдельное подключение, а обработчики событий и агенты по-прежнему пишутся в основную БД. Методы Tools\Database::* получили параметр ?Connection, в Context добавили isCurrentDevUpdater().
<?php declare(strict_types=1);
use Bitrix\Main\Application;
use Bitrix\Main\UpdateSystem\Migration\Context;
class vendor_stats extends CModule
{
public $MODULE_ID = 'vendor.stats';
protected function configureMigrationContext(Context $context): void
{
// подключение 'stats' описано в секции connections файла .settings.php
$context->setConnection(Application::getConnection('stats'));
}
}
Migration\IndexNameProcessor::process() в PostgreSQL приводит имя индекса к виду ix_|ux_|ixf_ + таблица + назначение, имена длиннее 63 символов режет до 50 и добавляет 12 символов sha256, а в текущем dev-апдейтере проверяет формат имени (исключение 1108). В DDL появились Column\ColumnState, ColumnStateData, enum ColumnAutoincrementType (Identity, SequenceDefault, None) и AlterTableData::getColumnState(). При расширении автоинкрементной колонки рендерер PostgreSQL генерирует ALTER SEQUENCE … AS bigint. Проверка сайта теперь требует в PostgreSQL standard_conforming_strings = on.
Посмотрите на REST v3 и мелочи интерфейса
В Bitrix\Main\Infrastructure\Rest\Controller лежат REST v3-контроллеры main, наследники Bitrix\Rest\V3\Controller\RestController с DTO, мапперами и сервисами: Like (scope rating), Smile и SmileSet (smile), User\Agreement и User\Consent (userconsent), User\History и User\History\Fields (user), Userfieldconfig (userfieldconfig). Старые фильтры переводит Support\LegacyQueryConverter.
В интерфейсе main-ui-select получил параметр enableSearch: поиск для одиночного выбора включается, если в списке не меньше 10 пунктов, и шаблоны main.field.enum включают его для списков с DISPLAY = UI. Компонент main.mail.form напоминает о забытом вложении (опция main:mail_form_attachment_reminder, по умолчанию Y), понимает общие подписи из модуля mail и запоминает выбор подписи. У поля from появились параметры senderIdName и mailboxIdName, они выводят скрытые input с ID отправителя и ящика.
БД
Новых таблиц нет. В install/mysql/install.sql и install/pgsql/install.sql у b_main_mail_sender появился индекс по (PARENT_ID, PARENT_MODULE_ID) для поиска отправителя по ящику: IX_B_MAIN_MAIL_SENDER_PARENT_ID и ix_b_main_mail_sender_parent_id_parent_module_id.
b_main_mail_sender.EMAIL теперь хранится в нижнем регистре. Старые строки дочищает степпер Bitrix\Main\Update\SenderEmailNormalization, его можно приостановить опцией main:sender_email_normalization_stop = Y, а строки, которые не удалось записать, попадают в журнал с типом MAIL_SENDER_NORMALIZATION_FAILED. Где степпер ставится в очередь, в коде модуля не видно.
ContentReplacer работает на существующей b_file_version (PK ORIGINAL_ID, UNIQUE по VERSION_ID, META типа text) и пишет в META ключи versionOwner и obsoleteFileId.
Мелочи и находки
ContentReplacerв «Управлении сайтом» пока ниоткуда не вызывается, поиск поbitrix/modulesнаходит только сам класс. Комментарий в нём ссылается на «существующие» связи с ключомversionOwner, но в этой версии таких нет.perfmon/classes/general/keeper.phpдо сих пор разбираетSTART_EXEC_EVENTS_*черезexplode(' ', …). Пока perfmon не обновят, с включённым монитором производительности будет предупреждение о несуществующем ключе массива, а интервал теперь измеряет обработчикиOnAfterEpilogвместо отправки счётчиков.- Напоминание о вложении работает на регулярках из lang-файла, куда нарочно заложены опечатки:
влажени,прекреп,прекрип,прлага. - В старом
Sender::add()обработчикOnBeforeEventSendрегистрировался только при непустой$smtpConfig, но в методе эта переменная не определялась, так что код не срабатывал никогда. Теперь письмо с кодом подтверждения уходит сContext::setAutomaticCustomSmtpEnabled(false). SenderEmailNormalizationсравнивает адреса в PHP. По комментарию в коде, в MySQL из-за collation условиеEMAIL <> LOWER(EMAIL)ничего не находит.- Готовится тип пользовательского поля
rich_text, создать его нельзя, пока выключен флагBitrix\UI\Config\Feature\RichTextUserFieldFlag. ВUI\Copyrightзаодно добавили Mermaid, KaTeX, Marked, DOMPurify, Cytoscape.js и Floating UI, комментарии указывают наui/install/js/ui/mermaidиui/install/js/ui/floating-ui. main.mail.formпроверяетclass_exists('\Bitrix\Mail\Service\SharedSignature\SignatureResolver')под будущую версию модуля mail, а в комментариях ссылается на внутреннюю спецификацию («AC-010», «API-02 contract»).CAdminList::IsDefaultFilter()читает$_REQUEST['set_default']без??, так что без этого параметра PHP 8 выдаст предупреждение.- Main перестаёт опираться на
CUpdateSystem:Migration\Filesпо умолчанию использует\CUpdateClient::class,UpdateServerDataParserвызываетCUpdateClient::ParseServerData,Migration\Table::writeLog()пишет черезCUpdateClient::AddMessage2Log.
Устаревшие и удалённые API в этой версии
| Символ | Статус | Чем заменять |
|---|---|---|
CHTTP::Download()
|
Deprecated |
Bitrix\Main\Web\HttpClient
|
CHTTP::PrepareData()
|
Deprecated |
http_build_query()
|
BX.Main.PopupManager._popups
|
Deprecated |
BX.Main.PopupManager.getPopups()
|
BX.Main.PopupManager._currentPopup
|
Deprecated |
BX.Main.PopupManager.getCurrentPopup()
|
CUserCounterPage::setNewEvent()
|
Удалено | — |
BX.Main.PopupManager.handlePopupDestroy()
|
Удалено | — |
BX.Main.PopupManager.handlePopupShow()
|
Удалено | — |
BX.Main.PopupManager.handlePopupClose()
|
Удалено | — |