Кэш ускоряет сайт, но на активных проектах — особенно с большим каталогом — папки bitrix/cache и bitrix/managed_cache могут разрастаться до десятков гигабайт. Ручная очистка из админки неудобна, поэтому обычно настраивают фоновый агент, который постепенно удаляет просроченные файлы кэша.
Ниже — рабочий способ для PHP 8+, проверенный на боевом сайте.
Как это устроено в Битрикс
Битрикс хранит файловый кэш в каталогах:
| Каталог | Назначение |
|---|---|
/bitrix/cache/ | Основной файловый кэш компонентов |
/bitrix/managed_cache/ | Управляемый кэш (меню, справочники и т.д.) |
/bitrix/stack_cache/ | Стековый кэш |
/bitrix/html_pages/ | HTML-кэш (композит) |
В начале каждого .php-файла кэша записаны метки $datecreate и $dateexpire. Агент читает заголовок файла и удаляет только те записи, у которых срок жизни уже истёк.
Важно: агент не очищает весь кэш целиком. Живые (ещё не просроченные) файлы остаются — и это нормально. Если диск забивается из-за миллионов валидных записей, нужно дополнительно снижать
CACHE_TIMEв компонентах и ограничивать обход ботов.
Шаг 1. Функция очистки в init.php
Добавьте в /local/php_interface/init.php:
function clean_expire_cache($path = "")
{
if (!class_exists("CFileCacheCleaner")) {
require_once $_SERVER["DOCUMENT_ROOT"]
. "/bitrix/modules/main/classes/general/cache_files_cleaner.php";
}
$currentTime = time();
$endTime = (defined("BX_CRONTAB") && BX_CRONTAB === true)
? time() + 5 // на кроне — до 5 секунд за запуск
: time() + 1; // на хитах — не более 1 секунды
// При возобновлении агент может передать полный путь — приводим к относительному
if ($path !== "" && strpos($path, $_SERVER["DOCUMENT_ROOT"]) === 0) {
$path = substr($path, strlen($_SERVER["DOCUMENT_ROOT"]));
}
$obCacheCleaner = new CFileCacheCleaner("all");
if (!$obCacheCleaner->InitPath($path)) {
return "clean_expire_cache();";
}
$obCacheCleaner->Start();
$file = false;
while ($file = $obCacheCleaner->GetNextFile()) {
if (!is_string($file)) {
continue;
}
$dateExpire = $obCacheCleaner->GetFileExpiration($file);
if ($dateExpire && $dateExpire < $currentTime) {
unlink($file);
}
if (time() >= $endTime) {
break;
}
}
// Сохраняем позицию для следующего запуска
if (is_string($file)) {
$resumePath = (strpos($file, $_SERVER["DOCUMENT_ROOT"]) === 0)
? substr($file, strlen($_SERVER["DOCUMENT_ROOT"]))
: $file;
return 'clean_expire_cache("' . str_replace('"', '\\"', $resumePath) . '");';
}
return "clean_expire_cache();";
}
Почему именно так (PHP 8+)
В старых примерах из документации часто встречается строка:
$curentTime = mktime(); // ❌ не работает в PHP 8+
В PHP 7 и ниже mktime() без аргументов возвращал текущий timestamp. В PHP 8.0+ вызов без параметров вызывает фатальную ошибку ArgumentCountError, и агент падает при каждом запуске, так и не удалив ни одного файла.
Используйте time() — это корректный и совместимый способ.
Второй типичный баг: при возобновлении в агент передаётся полный путь вида /home/user/www/bitrix/cache/..., а CFileCacheCleaner::InitPath() ожидает путь от корня сайта: /bitrix/cache/.... Без нормализации агент сбрасывается в начало и ходит по кругу, не продвигаясь по каталогу.
Шаг 2. Регистрация агента
В админке: Настройки → Инструменты → Агенты → «Добавить агента».
| Поле | Значение |
|---|---|
| Модуль | main |
| Функция агента | clean_expire_cache(); |
| Интервал | 60 (секунд) или 300 |
| Активен | Да |
Либо программно (один раз):
CAgent::AddAgent(
"clean_expire_cache();",
"main",
"N", // не периодический — интервал от LAST_EXEC
60, // интервал в секундах
"",
"Y", // активен
ConvertTimeStamp(time(), "FULL")
);
Агент работает порциями: за один запуск обрабатывает файлы 1–5 секунд, запоминает позицию и продолжает со следующего вызова.
Обязательно: точка с запятой в имени агента
В поле «Функция агента» нужно писать именно clean_expire_cache(); — с ; в конце.
Битрикс выполняет агент через eval():
eval("\$eval_result=clean_expire_cache();");
Если в админке указать clean_expire_cache() без точки с запятой, получится невалидный PHP-код:
eval("\$eval_result=clean_expire_cache()"); // ❌ syntax error в PHP 8+
Агент падает с синтаксической ошибкой, остаётся в состоянии RUNNING = Y, LAST_EXEC не обновляется, RETRY_COUNT растёт — создаётся впечатление, что очистка «не работает».
Проверить имя в БД:
SELECT ID, NAME, RUNNING, LAST_EXEC, RETRY_COUNT
FROM b_agent
WHERE NAME LIKE 'clean_expire_cache%';
Исправить, если точка с запятой потерялась:
UPDATE b_agent
SET NAME = 'clean_expire_cache();', RUNNING = 'N', RETRY_COUNT = 0
WHERE NAME = 'clean_expire_cache()';
Шаг 3. Крон для агентов
Чтобы агенты запускались стабильно, а не только при заходах на сайт, настройте системный cron:
* * * * * bitrix test -f /home/bitrix/www/bitrix/modules/main/tools/cron_events.php && \
/usr/bin/php -f /home/bitrix/www/bitrix/modules/main/tools/cron_events.php
Путь к сайту замените на свой. При запуске через cron в cron_events.php определяется константа BX_CRONTAB, и функция работает до 5 секунд за итерацию вместо 1.
Диагностика: агент «не помогает»
Если место на диске продолжает уменьшаться, проверьте агент в БД (b_agent) или в админке:
| Симптом | Причина | Решение |
|---|---|---|
RUNNING = Y, LAST_EXEC пустой, RETRY_COUNT растёт | В NAME агента нет ; в конце (clean_expire_cache() вместо clean_expire_cache();) | Исправить имя, сбросить RUNNING = N |
RUNNING = Y, LAST_EXEC пустой, ошибки в логе | Фатальная ошибка в функции (часто mktime() на PHP 8+) | Исправить код, сбросить RUNNING = N |
| Кэш растёт, но файлы «свежие» | Удаляются только просроченные записи | Снизить CACHE_TIME, ограничить ботов |
upload/ занимает больше, чем bitrix/cache | Проблема не в кэше | Чистить загрузки, резервные копии, логи |
Сброс зависшего агента:
UPDATE b_agent
SET RUNNING = 'N', RETRY_COUNT = 0
WHERE NAME = 'clean_expire_cache();';
Проверка функции из CLI:
cd /home/bitrix/www
DOCUMENT_ROOT=/home/bitrix/www php -r "
\$_SERVER['DOCUMENT_ROOT'] = '/home/bitrix/www';
define('NO_KEEP_STATISTIC', true);
define('NOT_CHECK_PERMISSIONS', true);
define('BX_CRONTAB', true);
require 'bitrix/modules/main/include/prolog_before.php';
echo clean_expire_cache() . PHP_EOL;
"
Если видите ArgumentCountError: mktime() — код не адаптирован под PHP 8.
Что ещё можно сделать
- Снизить время кэширования в шаблонах компонентов каталога (
CACHE_TIME— часто стоит 36000, то есть 10 часов). - Ограничить ботов в
robots.txtи на уровне веб-сервера — каждый уникальный URL создаёт новую запись кэша. - Встроенная очистка Битрикс — при инвалидации кэша из админки или кода срабатывает
Cache::delayedDelete()через очередьb_cache_clean_path. Это дополняет, но не заменяет агент по просрочке. - Мониторинг размера — периодически смотрите
du -sh bitrix/cache bitrix/managed_cache upload.
Итог
Автоматическая очистка просроченного кэша в Битрикс — стандартная практика: функция clean_expire_cache() + агент + cron. На PHP 8+ обязательно:
time()вместоmktime();- относительные пути
/bitrix/cache/...при возобновлении агента; clean_expire_cache();с точкой с запятой в поле функции агента;- контроль зависшего агента в таблице
b_agent.
Это не панацея от разросшегося каталога, но убирает «мёртвый» кэш без ручного вмешательства и предотвращает ситуацию, когда диск забивается файлами с истёкшим сроком жизни, которые никто не удаляет.
