Мы довели до 21.0 копии стендов с 15.0 по 20.0 и чистую установку 12.0 в windows-1251: при PHP 8.0 и новее ни одной ошибки PHP ни на сайте, ни в админке. Сломалось другое: на PHP 7.4 после заливки файлов белый экран, а архив 21.0 молча перезаписывает ваши .htaccess и robots.txt. Пропавшие ссылки в подписях, на которые жалуются на форуме, вообще родом из 18.0: кто прыгает на 21.0 с 17-й версии, видит это впервые и винит 21.0.
Коротко#
- До файлов 21.0 нужен PHP 8.0+ с расширением intl.
- База обновляется за секунды: с 15.1 — 10 с, с 20.0 — одна. На копии со 100 тысячами новостей шаг 20.0 → 21.0 шёл 28 секунд одним HTTP-запросом, и на хостинге с коротким таймаутом он может оборваться.
- В архиве 21.0 лежат
.htaccessиrobots.txt. Зальёте «всё, кроме шаблонов» — ваши редиректы и robots перезапишутся. - С 12.0 в windows-1251 до 21.0 дошли за один проход: 25 шагов и конвертация в UTF-8.
Как мы проверяли#
Всего 16 исходных версий: 15 стендов с 15.0 по 20.0 и отдельно поставленная DLE 12.0. Двадцать первая — цель, её не считаем. Стенды остались нетронутыми: для каждого делали копию в подпапку со своей копией базы. Обновляли по разделу «Обновление скрипта» из документации 21.0. Файлы из upload/ заливали поверх, кроме templates/. Шаги базы запускали теми же запросами, что шлёт кнопка «продолжить» в мастере admin.php?mod=upgrade, только скриптом, чтобы пройти 16 копий подряд. После этого открывали главную, новость с комментариями, поиск, профиль, регистрацию, RSS и пять разделов админки, затем смотрели журнал ошибок PHP.
Дистрибутив — dle21_0.zip от 19 сентября 2026 года. Есть и сборка от 17 сентября с тем же номером версии, но другими файлами админки. Свою можно узнать по размеру public/adminpanel/javascripts/application.js: 275 314 байт в сборке от 19.09, 275 677 — в сборке от 17.09.
С какой версии на 21.0 — что было#
На стендах немного данных: около 20 новостей, 15 комментариев и 13 пользователей. PHP в таблице тот, на котором живёт стенд. С 15.1 и 15.2 просто больше шагов, отсюда и 10 секунд.
| Было | PHP | Шагов базы | Время базы | Страницы |
|---|---|---|---|---|
| 15.0 | 7.4 | — | — | 500, пустой ответ |
| 15.0 | 8.0 | 15 | 10,1 с | все 200 |
| 15.1 | 8.0 | 14 | 10,3 с | все 200 |
| 15.2 | 8.0 | 13 | 10,0 с | все 200 |
| 15.3 | 8.1 | 12 | 6,3 с | все 200 |
| 16.0 | 8.1 | 11 | 6,2 с | все 200 |
| 16.1 | 8.1 | 10 | 5,8 с | все 200 |
| 17.0 | 8.2 | 9 | 4,9 с | все 200 |
| 17.1 | 8.2 | 8 | 4,8 с | все 200 |
| 17.2 | 8.2 | 7 | 5,5 с | все 200 |
| 17.3 | 8.3 | 6 | 4,3 с | все 200 |
| 18.0 | 8.3 | 5 | 3,5 с | все 200 |
| 18.1 | 8.1 | 4 | 3,6 с | все 200 |
| 19.0 | 8.2 | 3 | 3,1 с | все 200 |
| 19.1 | 8.3 | 2 | 4,2 с | все 200 |
| 20.0 | 8.3 | 1 | 1,0 с | все 200 |
Дольше всего везде шёл шаг 19.1 → 20.0, до 4,7 секунды. Промежуточные дистрибутивы не понадобились: в архиве 21.0 лежат скрипты обновления базы начиная с версии 7.0 (engine/inc/upgrade/*.php), мастер проходит их подряд.

PHP 7.4: белый экран#
Стенд 15.0 живёт на PHP 7.4. Файлы 21.0 мы залили прямо туда, и главная вместе с admin.php стали отдавать 500 и пустую страницу. В журнале Apache:
PHP Parse error: syntax error, unexpected '=>' (T_DOUBLE_ARROW) in …/engine/init.php on line 146
PHP Fatal error: Uncaught Error: Call to undefined function str_ends_with() in …/engine/inc/include/functions.inc.php:2993
С 145-й строки engine/init.php начинается выражение match, а его в PHP до 8.0 нет. Системные требования 21.0 это и говорят: PHP 8.0 и выше, среди нужных расширений intl. Та же копия 15.0 на хосте с PHP 8.0 обновилась за 15 шагов без ошибок PHP.
Поэтому сайт на 15.x или 16.x сначала переводите на PHP 8.0+ и смотрите, всё ли работает (15.1 и 15.2 у нас на 8.0 живут), а файлы 21.0 заливаете отдельным шагом. На смене PHP может упасть что-то своё, самописные вставки или старые плагины, и пусть это случится на старом движке: откатить PHP проще. Intl проверяйте через phpinfo() на самом сайте. php -m в консоли часто показывает другой PHP, не тот, что у сайта. Как быть с сайтами на 12.x, ниже в отдельном разделе.
Дальше 8.3 сайт на 21.0 мы не запускали. Проверили только синтаксис: php -l на PHP 8.4 и 8.5 по всем 329 PHP-файлам дистрибутива ошибок не нашёл.
Что 21.0 удаляет при обновлении#
Кроме индексов, шаг базы 20.0 → 21.0 (engine/inc/upgrade/20.0.php) удаляет файлы и настройки:
| Что | Где | Кого касается |
|---|---|---|
Удаляются engine/classes/geoip/ip2location.class.php и geo.base.dat |
геобаза теперь country.bin, asn.bin, dbreader.class.php |
модули, которые подключали ip2location.class.php напрямую |
Удаляются public/masha, public/fonts/inter, public/html5player/player.js и player.css |
— | шаблоны, которые грузили эти файлы сами |
Из config.php уходят allow_smartphone, allow_smart_images, allow_smart_video, allow_smart_format, mobile_news, mail_bcc |
мобильного шаблона Smartphone больше нет | сайты с отдельной мобильной версией: телефоны будут получать основной шаблон, проверьте его на узком экране |
Новые таблицы dle_mail_campaigns, dle_mail_campaign_users |
рассылки | — |
Индексы у 19 таблиц перестраиваются, старые одиночные (approve, tag, news_id и др.) удаляются |
у dle_post появляются семь составных индексов |
большие базы: это и есть долгий шаг |
Одно изменение мы нашли только чтением кода. В engine/modules/functions.php 21.0 функция http_get_contents проверяет SSL-сертификат сервера, к которому обращается (CURLOPT_SSL_VERIFYPEER включён, в 20.0 был выключен). Через неё идут вход через соцсети (engine/classes/social.class.php), проверка обновлений DLE и плагинов. На хостинге со старым набором корневых сертификатов эти функции могут перестать отвечать. Сами мы такого не встречали. Грубо проверить можно командой curl -I https://dle-news.ru/ с сервера: ошибка сертификата — повод попросить хостера обновить ca-certificates. Только PHP может брать свой набор сертификатов (curl.cainfo, openssl.cafile в php.ini), и консоль тогда покажет не то, что видит сайт.
Шаблоны в архиве 21.0 спрятаны в templates/default_templates.zip, и набор там другой: Air, Chronicle, Cover, Default_Images, Flow, Hub, Overview. В 20.0 были Default, Green, Red и smartphone. Папку templates/ при ручном обновлении не заливают, так что сайт остаётся на своём шаблоне. На всех копиях старые шаблоны открылись без ошибок. Новые теги 21.0 в них сами не появятся, список правок DLE ведёт на dle-news.ru/templates-changelog.html.
Большая база: сколько ждать и что делать при 504#
На маленьких стендах шаг 20.0 → 21.0 занимает около секунды. Для проверки на объёме живого сайта мы раздули копию 20.0 до 100 480 новостей и 511 440 комментариев, это 1 095 МБ данных с индексами. Сервер: 4 ядра, 5 ГБ памяти, MariaDB 11.4, плюс обычная рабочая нагрузка.
Шаг шёл 28 секунд, и всё это один ajax-запрос, ответа на который ждёт мастер. max_execution_time DLE снимает сама, а таймаут веб-сервера остаётся. Обрежет хостинг ответ раньше, чем закончится перестройка, — мастер покажет «HTTP Error:» с кодом ответа, обычно 504 или 502. На своём сервере поднимите таймаут на время обновления: в nginx это fastcgi_read_timeout или proxy_read_timeout, в Apache — Timeout. На виртуальном хостинге попросите поддержку или обновляйтесь ночью. dle-news.ru в описании релиза советует то же: тихие часы и снятые лимиты. Базу вдвое больше мы не гоняли; прикидываем, что это около минуты.
Если 504 всё-таки случился, по коду шаг можно повторить. В upgrade/20.0.php номер версии записывается в config.php уже после запросов к базе, поэтому оборванный шаг оставляет 20.0, и мастер предложит его снова. Индексы он добавляет только недостающие, сверяясь с SHOW INDEX. Обрыв мы специально не устраивали, это по коду. Если повтор не помог, восстанавливайте копию (шаг 1 порядка ниже).
Жалобы с форума: что мы повторили#
Три сентябрьские темы с форума dle-news.ru мы повторили на стендах.
Ссылки в подписи пропадают — с 18.0#
Тема: «Не сохраняются ссылки в подписи пользователя после обновления до DLE 21.0». Мы сохраняли подпись через форму профиля на сайте от имени администратора и смотрели, что легло в dle_users.signature.
| DLE | [url=…]…[/url] |
<a href="…"> |
|---|---|---|
| 15.1, 17.2, 17.3 | становится рабочей ссылкой | вырезается, остаётся текст |
| 18.0, 18.1, 19.0, 19.1, 20.0, 21.0 | остаётся текстом [url=…] |
вырезается, остаётся текст |
Подписи, сохранённые до 18.0, лежат в базе с готовым <a> и после обновления показываются со ссылкой. Ломает их первое сохранение профиля. Форма на 18.0+ показывает старую подпись HTML-кодом, и при сохранении <a> вырезается. На 17.3 та же форма подставила бы BB-код [url=…], и ссылка пережила бы пересохранение.

Узнать, сколько у вас таких подписей:
SELECT COUNT(*) FROM dle_users WHERE signature LIKE '%<a %';
Штатно вернуть ссылки в подпись нельзя: в 18.0+ форма профиля (engine/modules/profile.php) и редактирование пользователя в админке (engine/inc/editusers.php) пропускают подпись через фильтр, который вырезает весь HTML, а [url] больше не разбирают. Плагином — можно.
Мы собрали signature-links.xml: четыре правки, две на форму профиля, две на админку. После обычной обработки DLE плагин превращает [url=https://…]текст[/url] в ссылку, точно такую, какую хранила 17.3, а в форме редактирования показывает её обратно как [url=…], поэтому пересохранение ссылку больше не убивает. Главное в нём — одна строка:
$signature = preg_replace_callback( '#\[url=(https?://[^\]\s\\\\<>]+)\](.+?)\[/url\]#i', function ( $m ) {
return '<a href=\"' . $m[1] . '\" target=\"_blank\" rel=\"noopener external noreferrer\">' . $m[2] . '</a>';
}, $signature );
Адрес пропускается только с http:// или https://, без пробелов, кавычек и угловых скобок. Проверили на копии, обновлённой до 21.0: обычная ссылка сохраняется и пересохраняется; [url=javascript:…] и адрес с кавычкой и onmouseover остаются текстом; <a> и <script>, вписанные руками, вырезаются, как и без плагина; старая подпись с <a> после сохранения сохраняет ссылку; из админки («Редактирование пользователей») тоже работает. Условие — DLE 20.0 и выше, но гоняли мы плагин на 21.0.
«Ссылки в старых комментариях ведут на главную». У нас не повторилось#
Тема: «Внутренние ссылки в старых комментариях ведут на главную страницу после обновления до DLE 21.0». На копии 20.0 мы оставили комментарии с внутренними ссылками в разном виде: полный адрес новости, относительный /…/158-….html, http:// вместо https, index.php?newsid=158 и старый leech-формат с engine/go.php. Часть добавили через ту же форму, что и посетители, часть прямо в базу. После обновления до 21.0 HTML ссылок совпал байт в байт, каждая внутренняя вела на свою новость. С включённой настройкой «Обрабатывать неверные URL ЧПУ» неверная категория, старое имя новости и ?newsid давали 301 на правильный адрес новости. Leech-формат до конца проверить не вышло: engine/go.php на нашем сервере закрыт nginx.
Если у вас они всё же ведут на главную, смотрите плагины, которые меняют ЧПУ, или правила в .htaccess/nginx, в том числе .htaccess, перезаписанный при заливке файлов.
Можно ли выключить PRISM#
Тема: «Можно ли в DLE 21.0 отключить PRISM?». Настройкой — нельзя, плагином — да, и это пять строк.
PRISM — подсветка кода, public/prism/prism.js, 52 440 байт. Переключателя в engine/inc/options.php 21.0 нет. Скрипт подключается сам, как только на странице встречается <pre: в engine/modules/main.php (строка 410 в 21.0, 402 в 20.0), а для комментариев и личных сообщений, которые приходят аяксом, — ещё в четырёх файлах engine/ajax/: addcomments.php, comments.php, editcomments.php, pm.php.
Мы собрали плагин, который заменяет все пять условий на if (false) {: disable-prism.xml. Ставится как обычный плагин: «Управление плагинами» → загрузить файл. Файлы движка он не трогает, и удаление плагина всё возвращает. Проверили на копии сайта, обновлённой до 21.0: без плагина на странице с <pre> грузится prism.js, с плагином — нет, блок <pre> остаётся на месте, просто без подсветки. Все пять правок применились, журнал ошибок плагина пуст. Условие в плагине — DLE 20.0 и выше: в 20.0 эти строки такие же, но сам плагин мы гоняли только на 21.0.
Операция в плагине выглядит так (остальные четыре — то же самое для своего файла):
<file name="engine/modules/main.php">
<operation action="replace">
<searchcode><![CDATA[if (strpos($tpl->result['main'], "<pre") !== false) {]]></searchcode>
<replacecode><![CDATA[if (false) {]]></replacecode>
</operation>
</file>
С 12.x сразу на 21.0#
Вопросы на форуме вида «правильное обновление с 12.1 до 20» мы проверили на чистой DLE 12.0 в windows-1251 с тремя демо-новостями: поставили её на PHP 7.4, добавили комментарий с кириллицей и довели до 21.0 на PHP 8.0. Версии 13.x и 14.x не проверяли.
Сначала упёрлись в PHP. На 8.0 версия 12.0 не открывается:
PHP Fatal error: Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array, null given in …/engine/init.php:86
А 21.0 не открывается на 7.4. Общего PHP для двух версий нет: мы проверили 8.0, и 12.0 на нём уже падает. Поэтому переключение PHP на 8.x и заливка файлов 21.0 делаются в одно окно, сразу за ними вход в админку. Пока это идёт, сайт лежит, так что без полной копии не начинайте.
Сами шаги базы прошли гладко. Мастер показал 25 шагов, от 12.0 до 21.0 (с 12.1 было бы 24), и прошёл их за 7,8 секунды. Потом админка сама перевела на конвертацию в UTF-8. До неё в админке вместо названия группы «Администраторы» стоят ромбики с вопросом.

Мастер конвертирует таблицы по одной, затем шаблоны, и в самом конце пишет utf8mb4 в engine/data/dbconfig.php. 59 таблиц — 8,5 секунды. Кириллица в новостях и комментариях цела.
Ловушку мы нашли своей же ошибкой: в нашем скрипте шаг с dbconfig.php ушёл раньше таблиц. После этого мастер бодро ответил «Конвертация базы данных не требуется. Все таблицы в актуальной кодировке.», хотя все 59 таблиц оставались в cp1251. Он верит строке в dbconfig.php, таблицы не проверяет. У вас так выйдет после оборванного мастера или ручной правки файла. Проверка:
SELECT table_collation, COUNT(*)
FROM information_schema.tables
WHERE table_schema = 'имя_базы'
GROUP BY 1;
Увидели cp1251_general_ci — верните в dbconfig.php define ("COLLATE", "cp1251"); и пройдите конвертацию заново.
Порядок обновления, который мы бы использовали сами#
- Сделайте полную копию файлов и базы, пока сайт работает. Команды — из папки на уровень выше
public_html:Откат, если что-то пошло не так, — вернуть и то и другое (и версию PHP, если меняли):tar czf site-before-21.tgz public_html mysqldump --single-transaction -u ПОЛЬЗОВАТЕЛЬ -p ИМЯ_БАЗЫ > db-before-21.sqlrm -rf public_html && tar xzf site-before-21.tgz mysql -u ПОЛЬЗОВАТЕЛЬ -p ИМЯ_БАЗЫ < db-before-21.sql - Проверьте PHP и intl. При DLE 15.x–20.0 и PHP ниже 8.0 переходите на 8.0+ заранее, отдельным шагом. Сайт на 12.x меняет PHP и файлы 21.0 в одно окно.
- Сохраните свои
.htaccessиrobots.txt: вupload/21.0 лежат свои, и заливка их перезапишет. Эти два файла в 21.0 такие же, как в дистрибутиве 20.0, так что ничего нового движку от них не нужно.engine/data/в архиве пустой,config.phpиdbconfig.phpне тронутся. - Когда есть возможность, прогоните всё сначала на копии: подпапка или поддомен, копия базы, в
engine/data/config.phpпоправитьhttp_home_url, вdbconfig.phpимя базы. - Закройте сайт: «Настройка системы» → «Выключить сайт». Группа «Администраторы» отключённый сайт видит, в админку вы попадёте. Потом залейте
upload/из архива 21.0 поверх, кромеtemplates/и двух файлов из шага 3, и удалитеinstall.php. С SSH — из папки на уровень вышеpublic_htmlи от пользователя сайта, а не от root, иначе новые файлы будут чужими и мастер споткнётся о права:Через FTP или файловый менеджер хостинга то же самое: содержимоеrsync -a --exclude '/templates/' --exclude '/.htaccess' --exclude '/robots.txt' upload/ public_html/ rm public_html/install.phpupload/, кроме папкиtemplatesи этих двух файлов, поверх с заменой. Это 1 318 файлов, по FTP заливка займёт минуты. - Зайдите в
admin.php. Админка сама откроет «Мастер обновления DataLife Engine», нажмите «продолжить» и не закрывайте вкладку. Если мастер пишет «Обнаружено отсутствие прав доступа на запись» и называет/engine/cache/system/, папки нет или она принадлежит не тому пользователю. Мы наткнулись на это, когда удалили кэш от root: создайте папку и отдайте её пользователю, от которого работает PHP. Кэш после шагов мастер чистит сам. Сайт на windows-1251 после шагов базы попадёт на конвертацию в UTF-8. - Убедитесь, что версия действительно сменилась: в
engine/data/config.phpдолжно быть'version_id' => '21.0'. - Пройдите сайт: главная, новость с комментариями, поиск, профиль, регистрация, RSS, журнал ошибок PHP хостинга.
Проверено на: DLE 12.0, 15.0–20.0 → 21.0 (сборка 19.09.2026), PHP 7.4, 8.0, 8.1, 8.2, 8.3 (8.4 и 8.5 — только синтаксис), MariaDB 11.4; копии стендов dlemod.com, 27.09.2026.
Проверено на: DLE 12.0, 15.0–20.0 → 21.0, PHP 7.4–8.3 — 27.09.2026
Частые вопросы
Можно ли обновиться с DLE 15 или 16 сразу до 21.0?
Да. В архиве 21.0 есть скрипты обновления базы начиная с версии 7.0, мастер проходит их подряд: с 15.1 у нас это 14 шагов и 10 секунд. Сайт перед этим должен работать на PHP 8.0 или новее.
Можно ли обновить DLE 12.x сразу до 21.0?
На чистой 12.0 в windows-1251 у нас получилось: 25 шагов базы за 7,8 секунды и конвертация в UTF-8. Но 12.0 не работает на PHP 8, а 21.0 — на 7.4, поэтому PHP и файлы меняются в одно окно, с полной копией наготове. 13.x и 14.x мы не проверяли.
Какая версия PHP нужна для DLE 21.0?
PHP 8.0 и выше с расширением intl. На PHP 7.4 файлы 21.0 дают ошибку 500: на сайте — unexpected '=>' в engine/init.php, в админке — undefined function str_ends_with().
Перезапишет ли обновление .htaccess и config.php?
В upload/ архива 21.0 лежат свои .htaccess и robots.txt, при заливке поверх они заменят ваши. Папка engine/data в архиве пустая, config.php и dbconfig.php не трогаются.
Как откатиться, если обновление сломало сайт?
Только из копии, сделанной до обновления: вернуть файлы из архива и залить дамп базы, а если меняли PHP — вернуть и его. Поэтому копию делайте до всего остального.
Что делать, если мастер обновления выдал HTTP Error 504 или 502?
Хостинг оборвал долгий запрос, обычно на перестройке индексов большой базы. По коду 21.0 номер версии пишется после запросов, так что мастер предложит шаг ещё раз; до повтора поднимите таймаут веб-сервера. Не помогло — восстанавливайте копию.
Почему в подписи пользователя не сохраняются ссылки?
С DLE 18.0 подпись из профиля на сайте не принимает ни BB-код [url], ни тег <a>. Старые подписи показываются со ссылкой, пока пользователь не сохранит профиль. Вернуть ссылки можно плагином signature-links.xml из статьи: он снова понимает [url=https://…]текст[/url].
Можно ли отключить PRISM в DLE 21.0?
Настройки нет: скрипт подключается сам на страницах с тегом <pre>. Отключается плагином из пяти правок, который заменяет эти условия на if (false); готовый файл disable-prism.xml — в статье.