БЕЗОПАСНОЕ РЕЗЕРВНОЕ КОПИРОВАНИЕ БД INSTANTCMS
10.11.2026. Вариант исходного форумного обработчика rx / bacap_bd.
Это исходник хука, НЕ установочный пакет дополнения. Через установщик CMS
этот ZIP устанавливать не нужно. Ядро и таблицы CMS не изменяются.
Требуется существующий компонент rx. Для другого компонента изменить имя
класса onRxCronBacapBd и путь. Совместимость по синтаксису: PHP 7.4+,
64-bit Linux, InstantCMS 2.17.2+. API cmsConfig/cmsMailer сверены с 2.18.2.
Реальные сайт, СУБД и почтовый сервер автора не были доступны для проверки.
УСТАНОВКА
1. Сохранить исходный cron_bacap_bd.php и временно отключить эту задачу.
2. От имени пользователя, который запускает PHP cron, создать отдельную
папку вне всех каталогов сайтов, alias и открываемых по HTTP хранилищ:
mkdir -m 700 /absolute/private/icms-db-backups
Родитель должен существовать; все предки — без записи группе/остальным.
Пример пути условный. Не размещать в public_html, uploads, cache или /tmp.
Проверка кода учитывает известные CMS web-root, но не знает alias nginx
и виртуальные хосты. Исключить HTTP-доступ обязан администратор сервера.
3. В начале PHP-файла задать BACKUP_DIR и DUMP_BINARY. Папка должна иметь
права ровно 0700 и принадлежать пользователю cron. Указать реальный полный
путь к mysqldump / mariadb-dump, соответствующему серверу БД.
4. По умолчанию EMAIL_TO пуст: создаются только локальные SQL + SHA-256.
Для почты указать свой адрес в EMAIL_TO. Требуется расширение PHP zip
с AES-256; скрипт проверяет шифрование и расшифрованный SHA-256 перед отправкой.
Задать ICMS_BACKUP_ZIP_PASSWORD в защищенном окружении задания cron.
Пароль — случайный, не менее 24 символов; лучше 32 случайных байта в hex.
Хранить отдельно в менеджере паролей. Не помещать в URL, командную строку,
письмо с архивом, публичную инструкцию или репозиторий.
Учесть: среда задания cron обычно отличается от среды терминала.
5. При нестандартном подключении задать ICMS_BACKUP_DB_PORT и/или
ICMS_BACKUP_DB_SOCKET в окружении. db_host должен быть хостом, а не URL
или строкой host:port. Пароль БД читается из загруженной конфигурации CMS.
Нестандартные имена БД с пробелами/Unicode намеренно отклоняются.
6. Заменить только файл:
system/controllers/rx/hooks/cron_bacap_bd.php
Файл должен иметь обычные права исходника (например 0644), не 0777.
7. В штатном планировщике: компонент rx, хук bacap_bd, например 1440 минут.
Не создавать вторую такую же задачу. Cron сайта запускается через PHP CLI:
/usr/bin/php -f /absolute/path/to/site/cron.php example.org
Это команда всего планировщика сайта, не отдельного PHP-файла хука.
Не снимать CLI-защиту в cron.php. Новый хук намеренно не работает через HTTP.
8. Первый запуск — на тестовой копии; проверить журнал PHP, SQL, SHA-256,
восстановление и при необходимости доставку и расшифровку письма.
После проверки включить задачу на рабочем сайте.
ЧТО ИЗМЕНЕНО
— Никакого shell: proc_open получает массив аргументов.
— Пароль отсутствует в аргументах процесса; временный client.cnf — 0600
в папке 0700. Значения экранируются по формату option-файла MySQL.
— Ограничены время (600 с), размер дампа (2 GiB), занятое хранилище (10 GiB),
минимальный остаток диска (512 MiB), stderr (1 MiB).
— Проверяются код завершения, размер и завершающий маркер mysqldump.
Успешный файл получает итоговое имя только после этих проверок.
— Один запуск на папку через flock. Разным сайтам нужны разные папки.
— Временные файлы удаляются в finally и shutdown; остатки после SIGKILL
убираются при следующем запуске под блокировкой. При отключении задачи
удалить .icms-work-* вручную из защищенной папки после остановки процессов.
— Локальный готовый SQL НИКОГДА не удаляется автоматически.
— Почта содержит только проверенный ZIP AES-256. При любой ошибке отправки,
отсутствии пароля/zip или превышении лимита SQL остается на диске.
— Порог вложения — 10 MiB (и исходного SQL тоже); base64 увеличит письмо.
Это консервативный лимит, а не попытка сжать большую БД до любого размера.
— Успех send() означает прием почтовым транспортом, а не доставку адресату.
Готовый SQL остается даже после успешной отправки. Открывать ZIP нужно
программой с поддержкой AES-256 ZIP (например совместимым архиватором).
ОГРАНИЧЕНИЯ И ОБСЛУЖИВАНИЕ
— Локальный SQL не зашифрован: защищен правами доступа. Пользователь PHP,
root и скомпрометированный код того же сайта могут его прочитать.
Для защиты от взлома сервера нужна отдельная удаленная копия с версиями
и отдельными учетными данными. Загрузки в облако в этом варианте нет.
— Автоудаления старых копий нет намеренно: при лимите задача откажется
создавать новую. Настроить контроль журнала [rx backup] и заполнения диска;
удалять старые копии лишь после проверки независимой копии/восстановления.
Лимиты проверяются раз в 0,2 секунды: возможен небольшой перерасход;
жесткий лимит обеспечивает квота ОС, а не этот скрипт.
— --single-transaction дает согласованный снимок для InnoDB, при отсутствии
параллельных ALTER/DROP/RENAME/TRUNCATE. Для MyISAM/Aria и смешанных движков
этот вариант не гарантирует согласованность: нужен другой режим/окно
обслуживания. Не выполнять миграции схемы во время копирования.
— Включены routines/events/triggers. Их выгрузка требует соответствующих
прав БД. Отсутствие прав считается ошибкой; частичный SQL удаляется.
Для MySQL при ошибке PROCESS/tablespaces может потребоваться осознанное
добавление --no-tablespaces после проверки используемой структуры БД.
Не менять кодировку/GTID/TLS-параметры вслепую. Для удаленной БД отдельно
настроить проверяемое TLS-подключение для вашего клиента MySQL/MariaDB.
— --defaults-file изолирует обычные option-файлы. У MySQL также возможен
пользовательский .mylogin.cnf: проверить отсутствие конфликтующего login
path у пользователя cron; MySQL и MariaDB отличаются в этой части.
— Временный конфиг удаляется, но это не гарантированное стирание с SSD,
файловой системы, swap и снимков хостинга. При SIGKILL/power loss код
очистки выполнить невозможно; остатки закрыты правами 0700/0600.
— Этот код копирует БД, а не файлы сайта/uploads и не конфигурацию сайта.
— SHA-256 и завершающий маркер — проверка целостности, не тест восстановления.
— Возвращаемое false не следует считать системой уведомлений: cron CMS
может только обновить дату запуска. Контролировать журнал PHP отдельно.
ПРОВЕРКА ВОССТАНОВЛЕНИЯ
На изолированном тестовом MySQL/MariaDB, без подключения к рабочему сайту:
1. Сверить SHA-256 с файлом .sha256.
2. При использовании почты расшифровать ZIP локально и сверить SHA-256 SQL.
3. Импортировать SQL на тестовом сервере. В дампе есть CREATE DATABASE/USE
с исходным именем БД: не импортировать его на рабочий сервер для теста!
Учесть EVENT SCHEDULER: тестовый сервер не должен запускать события с
внешними побочными эффектами. Проверить таблицы, строки, русский текст,
emoji при их наличии, триггеры/процедуры и запуск тестовой копии сайта.
ОТКАТ
Отключить задачу, убедиться, что процесс завершился, вернуть исходный PHP.
Готовые SQL сохраняются. Изменений ядра/схемы БД этот хук не делает.
ИСТОЧНИКИ
instantcms.ru/forum/pfind/371434
docs.instantcms.ru/dev/controllers/core
docs.instantcms.ru/manual/settings/scheduler
docs.instantcms.ru/manual/settings/scheduler/task