Скрипт работает, работает — и обрывается на полпути. В логе появляется
Maximum execution time of N seconds exceeded, импорт останавливается
посередине, экспорт отдаёт обрезанный файл, а страница показывает белый экран
после долгой загрузки.
PHP ограничивает время выполнения скрипта параметром max_execution_time.
Разберём, где его менять, почему простое увеличение лимита помогает не всегда
и как переписать долгие операции так, чтобы они вообще перестали упираться в это ограничение.
Где меняется лимит
Способов несколько, и они действуют на разных уровнях.
В php.ini
max_execution_time = 300
Действует на все скрипты. Требует доступа к конфигурации и перезапуска PHP-FPM.
В .htaccess
php_value max_execution_time 300
Работает на Apache и в связке Nginx + Apache. На чистом Nginx с PHP-FPM не сработает.
Прямо в скрипте
<?php
set_time_limit(300); // 300 секунд с этого момента
set_time_limit(0); // без ограничения
Самый точечный вариант: лимит поднимается только для конкретной операции, а не для всего сайта. Именно так стоит поступать с импортом и выгрузками.
Важно: set_time_limit() сбрасывает отсчёт заново при каждом вызове.
Внутри длинного цикла его можно вызывать периодически, продлевая время.
Почему лимит не всегда помогает
Частая ситуация: max_execution_time подняли до 600, а скрипт всё равно
обрывается на 60-й секунде. Причина в том, что ограничений несколько, и срабатывает
самое строгое.
| Ограничение | Где задаётся | Признак |
|---|---|---|
max_execution_time |
PHP | Ошибка в логе PHP |
request_terminate_timeout |
PHP-FPM | Процесс убит, в логе FPM запись о таймауте |
fastcgi_read_timeout |
Nginx | Ошибка 504 Gateway Timeout |
Timeout |
Apache | Обрыв соединения |
max_input_time |
PHP | Обрыв при загрузке больших файлов |
Если вместо ошибки PHP вы видите 504 — упирается Nginx, и правка
max_execution_time ничего не даст. Про этот случай есть отдельный разбор:
Ошибка 504 Gateway Timeout в Битрикс.
Отдельно: в командной строке ограничение времени по умолчанию отсутствует. Скрипт, который падает по таймауту через браузер, спокойно отработает через консоль.
Нужна помощь с Битрикс?
Типичные ситуации на Битрикс
Импорт каталога
Загрузка большого файла товаров почти гарантированно упирается в лимит. Штатный импорт Битрикс решает это пошаговой обработкой: скрипт обрабатывает порцию записей, сохраняет позицию и перезапускается.
Обмен с 1С
Обмен разбит на шаги по тому же принципу. Если он обрывается, обычно дело не в самом лимите, а в слишком большом размере шага — его уменьшают в настройках обмена.
Агенты
Агент, выполняющийся на хите пользователя, ограничен тем же лимитом. Тяжёлому агенту место в cron, где ограничения времени нет.
Переиндексация поиска
Полная переиндексация большого сайта занимает часы. Запускать её нужно из командной строки, а не через административный интерфейс.
Правильное решение: разбить на шаги
Поднимать лимит до бесконечности — тупиковый путь: данных станет больше, и обрыв повторится. Долгие операции разбивают на порции.
Схема пошаговой обработки:
<?php
use Bitrix\Main\Config\Option;
$step = 500; // записей за проход
$processed = (int)Option::get('mymodule', 'import_offset', 0);
$result = CIBlockElement::GetList(
['ID' => 'ASC'],
['IBLOCK_ID' => 5],
false,
['nTopCount' => $step, 'nOffset' => $processed],
['ID', 'NAME']
);
$count = 0;
while ($item = $result->Fetch()) {
// обработка одной записи
$count++;
}
if ($count > 0) {
// запоминаем позицию и продолжим со следующего запуска
Option::set('mymodule', 'import_offset', $processed + $count);
} else {
// всё обработано, сбрасываем счётчик
Option::set('mymodule', 'import_offset', 0);
}
Такой скрипт никогда не упрётся в лимит: каждый запуск занимает секунды. Запускать его можно агентом или по cron.
Оптимизация вместо увеличения времени
Прежде чем поднимать лимит, стоит проверить, почему операция вообще такая долгая. Частые причины на Битрикс:
- Запрос внутри цикла. Классическая ошибка: выборка элементов, и для каждого — отдельный запрос за свойствами. Тысяча элементов превращается в тысячу запросов.
-
Выборка всех полей. Указывайте в
selectтолько нужное, особенно если у элементов много свойств. - Отсутствие индексов в самописных таблицах.
- Обращение к внешнему API в цикле. Сто запросов по секунде каждый — это сто секунд только на ожидание.
- Работа с изображениями. Генерация превью для тысячи товаров съедает и время, и память.
Часто оптимизация одного запроса сокращает время выполнения в десятки раз — и вопрос лимита снимается сам собой.
Диагностика
Понять, где именно скрипт проводит время, помогают замеры:
<?php
$start = microtime(true);
// ... блок кода ...
\Bitrix\Main\Diag\Debug::writeToFile(
round(microtime(true) - $start, 3) . ' сек — выборка элементов',
'TIMING',
'/local/logs/timing.log'
);
Расставив такие замеры по этапам, обычно быстро находишь один участок, который занимает почти всё время.
Частые ошибки
-
set_time_limit(0)на боевом сайте. Зависший скрипт будет висеть вечно, занимая процесс и соединение с базой. -
Правка
max_execution_timeпри ошибке 504. Упирается таймаут веб-сервера, а не PHP. - Запуск тяжёлых операций через браузер. Для импорта и переиндексации есть командная строка без ограничений.
- Увеличение лимита вместо оптимизации. Работает ровно до тех пор, пока данных не станет вдвое больше.
- Тяжёлые агенты на хитах. Ограничение бьёт по случайному посетителю, которому не повезло запустить агента.
Итог
Ошибка Maximum execution time exceeded означает, что скрипт превысил
отведённое PHP время. Поднять лимит можно через php.ini,
.htaccess или точечно вызовом set_time_limit() —
последний способ предпочтительнее.
Но если операция долгая по своей природе — импорт, обмен, переиндексация — правильное решение не в лимите, а в разбиении на шаги с сохранением позиции. Такой скрипт не упрётся в ограничение никогда, сколько бы данных ни было. А перед тем как менять настройки, стоит проверить, нет ли в коде запроса внутри цикла: чаще всего время уходит именно туда.
