Из названий было не видно, какая панель лежит в основе. Теперь версия стоит в H1 всех документов и галерей, а в начале README (обоих) добавлена строка об оригинале: HostinPL 5.6, авторы Samir Shelenko и Alexander Zemlyanoy, писалась под Debian 9 / PHP 7.0. Нумерация версии оставлена от оригинала. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
20 KiB
Русский · English
HostinPL 5.6 · Что изменено по сравнению с оригиналом
Оригинал: HostinPL 5.6 в виде «nulled»-сборки (форк Xopowblu-4EJlOBEK/HostinPL-5.6),
написанной под Debian 9 и PHP 7.0.
Ниже — всё, что мы поменяли, с указанием файлов и строк. Правки в коде панели лежат в panel/.
Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом.
1. Панель запущена на современном PHP
Оригинал написан под PHP 7.0. На PHP 8 часть кода падала насмерть. Сейчас панель работает на PHP 8.4: обход всех 21 раздела (главная, сервера, новости, статус, тикеты, веб-хостинг и вся админка) даёт 200 на каждом и ноль ошибок в логе.
| Файл | Было | Стало |
|---|---|---|
engine/engine_ftp/elFinder.class.php:4497 |
utf8_encode() — функция удалена в PHP 8.2, файловый менеджер падал с фатальной ошибкой |
Обёрнута в function_exists(), фолбэк mb_convert_encoding($str,'UTF-8','ISO-8859-1') |
application/views/admin/checksys/index.php:22 |
apache_get_modules() — существует только в Apache с mod_php, под nginx раздел «Проверка системы» отдавал 500 |
Обёрнута в function_exists(), иначе проверка по REQUEST_URI |
application/views/admin/index.php:215 |
$item['invoice_ammount'] использовался после foreach, при пустом списке счетов — Undefined variable |
Проверка isset() |
application/models/users.php:199-206 |
$city[1], $country[1], $countryCode[1] без проверки совпадения регулярки |
Проверки isset() |
application/controllers/common/loginheader.php:35 |
$_GET['ref'] без isset |
isset() + приведение к (int) |
Что оказалось ложной тревогой
Библиотека phpseclib 1.x в составе панели использует create_function(), удалённую в PHP 8.
Выглядело как блокирующая проблема, но проверка показала: phpseclib не подключается ни одним
include во всей панели — это мёртвый код. Связь с игровыми нодами идёт через нативное
расширение php-ssh2 (engine/libs/ssh2.php → ssh2_exec). Ничего чинить не потребовалось.
Так же безопасен get_magic_quotes_gpc() в elFinderConnector.class.php:320 — он закрыт
условием version_compare(PHP_VERSION,'5.4','<') && ..., и на PHP 8 до вызова дело не доходит.
2. Капча выключена и управляется из админки
Раньше капча была вшита жёстко: без валидных ключей Google войти в панель было невозможно,
на форме висело «ERROR for site owner: Invalid site key». Теперь появился флаг
captcha_enable в application/config.php (по умолчанию 0 — выключена).
Бэкенд. Во все четыре валидатора добавлена строка
if($this->config->captcha_enable != '1') return $result; перед проверкой капчи:
application/controllers/account/login.php— входapplication/controllers/common/loginheader.php— регистрация и форма обратной связи (2 места)application/controllers/tickets/create.php— создание тикета
Вёрстка. Пять виджетов капчи (4 в views/common/loginheader.php, 1 в views/tickets/create.php)
обёрнуты в <?php if(@$captcha_enable == '1'): ?>. Скрипт Google api.js подключается только при
включённой капче. Все вызовы grecaptcha.reset(...) заменены на
window.grecaptcha && grecaptcha.reset(...) — иначе при выключенной капче JavaScript падал
в обработчиках ошибок и формы переставали отвечать.
Админка. В views/admin/settings.php, вкладка «Прочие настройки», добавлен блок
«Защита от ботов (reCAPTCHA v2)»: переключатель Выключена/Включена и поля Site key и Secret key.
Проверено в обе стороны: при выключенной капче вход и регистрация проходят и пользователь реально создаётся в базе; при включённой — свежая сессия получает «Подтвердите, что вы не робот!» и виджет возвращается на страницу.
Осторожно при добавлении своих настроек. Механизм сохранения настроек ищет строки конфига по подстроке (
strpos). Поэтому флаг названcaptcha_enable, а неcaptcha: строкаcaptchaсодержится вrecaptchaиsecret_recaptcha, и сохранение перезаписало бы не тот параметр. Новые ключи не должны быть подстрокой существующих.
3. Закрыты уязвимости
Кратко (подробно с кодом — в БЕЗОПАСНОСТЬ.md):
- Две SQL-инъекции, доступные без авторизации в
application/models/users.php(createAuthLog()): в журнал входов без экранирования попадали пароль из формы и IP из заголовкаCF-Connecting-IP, который вообще не проверялся. Все значения теперь проходят через$this->db->escape()/(int), заголовок проверяетсяfilter_var(..., FILTER_VALIDATE_IP). - Пароли в открытом виде:
login.phpписал реальный пароль в таблицуauthlogпри каждой попытке входа, включая неудачные. Убрано. - XSS в скрытом поле
refформы регистрации — добавленhtmlspecialchars(). - Запрос к геосервису
ip-api.comвыполняется только для валидного IP и сurlencode().
4. Установщик переписан с нуля
Оригинальный install был опасен на любой современной системе:
echo "deb ... stretch main" > /etc/apt/sources.list— затирал список репозиториев и заменял его на Debian 9, после чего apt ломался- ставил
php7.0и жёстко правил/etc/php/7.0/apache2/php.ini - переводил MariaDB на
bind-address = 0.0.0.0без единого предупреждения - работал только при
/etc/issue.net==Debian9, иначе просто отказывался запускаться - пароли и токены генерировал, но нигде не сохранял — их можно было только записать с экрана
- при любой ошибке продолжал работу: все команды заканчивались на
> /dev/null 2>&1
Новые скрипты:
install-panel.sh — nginx, PHP 8.x (версия определяется автоматически), MariaDB, база со
случайным паролем, конфиг, планировщик, сторож автозапуска, создание администратора и финальная
проверка, что страница входа действительно отдаётся с формой. Идемпотентен: повторный запуск
не затирает уже загруженную базу. Креды пишутся в /root/.redl-panel-credentials (chmod 600).
set -euo pipefail — при ошибке скрипт останавливается, а не делает вид, что всё хорошо.
install-node.sh — Docker из официального репозитория, сборка образа, каталоги
/home/cp/gameservers/files, группа gameservers, MariaDB для баз игровых серверов, SteamCMD,
ProFTPD, настройка sshd с откатом конфига, если sshd -t не проходит. Перед началом проверяет,
может ли Docker вообще работать на этой машине (unshare -Ur), и честно предупреждает, если нет.
В конце печатает готовые данные для подключения локации и команды файрвола.
Ни один из скриптов не трогает /etc/apt/sources.list.
5. Образ игровых серверов пересобран
Оригинальный docker/Dockerfile.original-stretch собран на debian:stretch, а репозитории
Debian 9 отключены с 2023 года — образ больше не собирается, apt-get update внутри падает.
Новый docker/Dockerfile — на Debian 12 (bookworm), но обязательно с тегом debian:stretch:
это имя жёстко прописано в коде панели (application/models/servers.php:642,
docker create ... debian:stretch), менять его без правки панели нельзя.
Что внутри: 32-битные библиотеки (SA-MP, CRMP, MTA, старые CS собраны под i386), screen для
консолей, Java для Minecraft, Node.js 20 для RAGE:MP, gdb для разбора крашей.
Node.js берётся из NodeSource по HTTPS с проверкой ключа, а не как раньше.
6. Работа без systemd
Панель штатно рассчитана на systemd. В контейнерных VPS его нет, поэтому добавлены сторожа
на cron: /usr/local/bin/hostinpl-guard (панель) и /usr/local/bin/gamenode-guard (нода).
Раз в минуту (нода — раз в 2 минуты) они проверяют MariaDB, PHP-FPM, nginx, Docker и cron и
поднимают то, что упало; плюс задание @reboot для подъёма после перезагрузки.
Живость панели определяется HTTP-запросом к странице входа, а не поиском процесса по имени — поиск по шаблону ловил бы собственную командную строку сторожа.
7. Планировщик
Оригинал прописывал 9 заданий на публичный домен панели. Теперь они ходят на 127.0.0.1
(не зависит от DNS и внешней доступности) и получают таймауты -m, чтобы зависший запрос
не копился в процессах.
Грабля с токеном. Токен планировщика нельзя выцеплять из конфига простым
grep "'token'"— под это же условие попадает строка'yk_password1' => 'token', и в URL уезжают два значения через перевод строки, после чего задания молча не работают. В установщике токен пишется напрямую при генерации конфига.
8. Языки интерфейса: русский и английский
Оригинал был только на русском, весь текст вшит в шаблоны. В сборке появился слой перевода:
engine/main/lang.php— классLangи глобальный помощникt()application/lang/ru.php,application/lang/en.php— словари- Порядок выбора языка: параметр
?lang=→ cookielang→ заголовок браузераAccept-Language→ значение по умолчанию из конфига - Переключатель (RU / EN) в шапке кабинета, админки и в подвале страницы входа
- Фразы, которых нет в словаре, остаются на русском — из интерфейса ничего не может пропасть
Перевод применяется к готовому ответу через ob_start(), поэтому 200 файлов шаблонов
переписывать не понадобилось, и покрытие сразу распространяется на админку и письма.
Замена работает только на границах слов: без этого короткий ключ портил длинные слова
(«Мод» превращал «Модуль» в «Modуль», «день» делал из «деньги» «dayги»).
Полнота перевода
В словаре 1304 фразы — это весь текст, который панель показывает человеку: кабинет, заказ сервера, управление сервером (консоль с описанием всех RCON-команд, FTP, базы MySQL, файрвол, планировщик задач, автоустановка модов), тикеты, FAQ целиком, вся админка, письма и служебные сообщения планировщика.
Покрытие считается не на глаз: скрипт повторяет логику замены прямо на исходниках и показывает строки, которые останутся русскими. По нему непокрытых мест четыре, и все четыре такими и должны быть:
- «Русский» — подпись самого переключателя языка;
rus => Pyccĸийиukr => Українськав FAQ — это коды языков игрового сервера, а не интерфейс;- регулярное выражение проверки имени
/^([А-ЯЁ])([а-яё]{1,15})$/u— код, а не текст.
Отдельно поправлены два подводных камня, которые давали мешанину языков:
- предлог «в» был отдельной записью словаря и подменялся внутри ещё не переведённых предложений — получалось «at поле имя пользователя». Такие служебные слова переводятся только вместе с фразой;
- формат даты
d.m.Y в H:iсодержит русское «в» между датой и временем. Теперь он проходит черезt()(31 вызовdate()в 20 файлах), и в английском режиме получается30.07.2026 14:22.
Проверено живым обходом 45 страниц в английском режиме, включая формы создания и скрытые вкладки настроек. Подробности — в ИНСТРУКЦИЯ.md, раздел «Язык интерфейса».
9. Брендинг и даты
- Год в подвалах:
2020©→2026©(views/common/footer.php,views/common/loginheader.php) - Название и описание — REDL.IO:
application/config.php(description,keywords,mail_sender,mail_from), подвалы, раздел «Проверка системы» - Ссылки на сторонние сайты прежнего владельца сборки (
hostinpl.ru,osmp.ga) заменены наredl.io - Ссылки «Сообщество VK» на чужое сообщество заменены на
redl.io(footer.php,views/main/index.php,views/offline/index.php) - Все 15 шаблонов писем: шапка «REDL.IO / Хостинг с искусственным интеллектом», подпись «С уважением, Администрация REDL.IO»
Авторские копирайт-заголовки в коде не удалялись — они остались во всех файлах, где были изначально.
10. phpMyAdmin
Панель ссылается на /phpmyadmin из админки. Оригинальный установщик ставил phpMyAdmin через
Apache, что на nginx не работало. Теперь он ставится из репозитория дистрибутива и отдаётся
самим nginx.
Грабля за обратным прокси. nginx на адрес
/phpmyadmin(без слеша) отвечает редиректом и по умолчанию подставляет в него собственный порт, напримерhttp://panel.example.com:8095/phpmyadmin/. Если панель стоит за обратным прокси, такой адрес снаружи недоступен и ссылка из админки не открывается. Лечитсяabsolute_redirect off; port_in_redirect off;— это уже прописано в конфиге, который создаёт установщик.
Чего мы НЕ делали
- Не переписывали хеширование паролей. Панель хранит пароли как MD5 без соли
(
md5($password), колонкаvarchar(32)). Переход наpassword_hash()затрагивает вход, регистрацию, восстановление, смену пароля и требует миграции существующих пользователей. - Не переводили создание игровых серверов с Docker на что-то другое.
- Не удаляли
panel/application/public/js/proxy/proxy.php— файл обезврежен, но оставлен как свидетельство (см. БЕЗОПАСНОСТЬ.md). - Не тестировали платёжные шлюзы живыми платежами и VK-авторизацию.
- Не проверяли работу самих игровых серверов: для этого нужна нода с Docker.
Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом.