Увеличение периода выполнения PHP кода для предотвращения ошибок timeout
Способы увеличения времени выполнения PHP скриптов
Как программно изменить максимальное время выполнения скрипта?
Наиболее гибкий способ - использовать функцию set_time_limit() прямо в коде. Она позволяет установить лимит времени для текущего скрипта, при этом отсчёт начинается с момента вызова. Если передать 0, ограничение снимается.
set_time_limit(120); // 120 секунд
// или без лимита:
// set_time_limit(0);Time out php (увеличение времени выполнения скрипта php)
Функция set_time_limit() перезаписывает директиву max_execution_time из php.ini. Если скрипт уже работал некоторое время, новый отсчёт начнётся с текущего момента. Это удобно для длительных операций, например, обработки больших CSV-файлов или генерации отчётов.
Типичные проблемы:
- На некоторых хостингах вызов set_time_limit() может быть запрещён (директива disable_functions). В этом случае потребуется другой подход.
- Если скрипт превышает время, PHP выдаёт фатальную ошибку Fatal error: Maximum execution time exceeded. Обработать её через try-catch нельзя, но можно зарегистрировать функцию через register_shutdown_function() для выполнения действий перед завершением.
- При использовании set_time_limit(0) скрипт может выполняться бесконечно, что нагружает сервер. Рекомендуется всегда задавать разумный лимит.
Как установить глобальный лимит времени выполнения для всех скриптов?
Измените директиву max_execution_time в файле php.ini. Найдите строку max_execution_time = 30 и замените на нужное значение (в секундах). Для unbounded укажите 0.
max_execution_time = 120
После изменения перезапустите веб-сервер (Apache, Nginx) или PHP-FPM. Изменение повлияет на все скрипты, работающие в этом окружении.
Проблемы:
- Если у вас нет доступа к php.ini (например, на общем хостинге), этот вариант недоступен.
- Глобальная настройка может снизить безопасность: если какой-то скрипт зависнет, он будет потреблять ресурсы дольше.
Как временно изменить директиву из кода без прав на php.ini?
Функция ini_set() позволяет переопределить значение директивы max_execution_time на время выполнения текущего скрипта. Однако не все директивы можно менять в рантайме (это зависит от режима - PHP_INI_ALL или PHP_INI_PERDIR). Директива max_execution_time относится к PHP_INI_ALL, поэтому её можно использовать в скрипте.
ini_set('max_execution_time', 300); // 5 минут
Эффект аналогичен set_time_limit(), но при этом отсчёт начинается с момента начала выполнения скрипта, а не с момента вызова. При использовании ini_set() после некоторого времени скрипта, лимит может быть уже частично исчерпан. Поэтому предпочтительнее set_time_limit().
Ошибки:
- Если директива не разрешена для изменения (например, если хостинг ограничил ini_set для max_execution_time), вызов не повлияет на лимит.
- Использование ini_set() для установки 0 также снимет ограничение.
Как настроить таймаут через конфигурацию веб-сервера для конкретной директории?
Если используется Apache, можно добавить директиву php_value max_execution_time в файл .htaccess в нужной директории. Для этого должен быть включён модуль mod_php.
# .htaccess
php_value max_execution_time 120
Аналогично можно использовать php_admin_value, если у вас есть доступ к основному конфигу Apache. На Nginx такой подход не работает - там используется FastCGI, и директивы передаются через настройки PHP-FPM.
Проблемы:
- Директива php_value работает только в Apache с mod_php. В режиме FastCGI/FPM она игнорируется.
- Некоторые хостинги запрещают использование php_value в .htaccess из соображений безопасности.
Как увеличить время ожидания ответа от PHP при использовании сервера Apache или Nginx?
Помимо внутреннего таймаута PHP существуют таймауты на уровне веб-сервера. Для Apache директива Timeout задаёт максимальное время ожидания ответа от PHP-процесса (в секундах).
# Apache в httpd.conf или virtual host
Timeout 180
Для Nginx используется директива proxy_read_timeout (если PHP работает через FastCGI, то fastcgi_read_timeout).
# Nginx в server или location block
location ~ \.php$ {
fastcgi_read_timeout 180;
...
}
Эти настройки должны быть не меньше, чем лимит PHP, иначе скрипт будет прерван сервером раньше.
Возможные ошибки:
- Несоответствие таймаутов: если PHP настроен на 300 секунд, а сервер на 120, скрипт будет прерван сервером.
- В некоторых случаях (например, при использовании балансировщиков) могут быть дополнительные таймауты.
Расширенные примеры настройки времени выполнения PHP
Пример 1. Использование set_time_limit() с учётом уже прошедшего времени
Функция set_time_limit() сбрасывает счётчик на ноль. Если скрипт уже выполнялся 10 секунд, а вы вызываете set_time_limit(30), то общий лимит станет 10 + 30 = 40 секунд. Это позволяет продлевать время для длительных операций.
echo "Начало выполнения: " . date('H:i:s') . "\n";
// Эмуляция 5-секундной работы
sleep(5);
echo "Прошло 5 секунд, вызываем set_time_limit(10)\n";
set_time_limit(10);
sleep(8); // всего прошло 13 секунд, лимит 10 с момента вызова, но осталось 2 секунды
echo "Скрипт завершился через 13 секунд, лимит не превышен";
Начало выполнения: 10:00:00 Прошло 5 секунд, вызываем set_time_limit(10) Скрипт завершился через 13 секунд, лимит не превышен
Если бы sleep(8) заменить на sleep(12), скрипт был бы прерван.
Пример 2. Снятие ограничения времени через set_time_limit(0) и контроль ресурсов
Установка нуля означает бесконечное выполнение. Это может быть опасно, поэтому используйте вместе с проверкой времени вручную.
$startTime = time();
$maxExecution = 60; // ограничим сами
set_time_limit(0);
while (true) {
// Длительная операция
if (time() - $startTime > $maxExecution) {
echo "Превышено ручное ограничение в 60 секунд";
break;
}
// ...
}
Превышено ручное ограничение в 60 секунд
Пример 3. Обработка превышения времени через register_shutdown_function
Хотя фатальную ошибку таймаута нельзя перехватить, можно зарегистрировать функцию, которая выполнится при завершении скрипта, и проверить последнюю ошибку.
register_shutdown_function(function() {
$error = error_get_last();
if ($error && $error['type'] === E_ERROR && strpos($error['message'], 'Maximum execution time') !== false) {
echo "Скрипт был прерван по таймауту после " . $error['file'] . ":" . $error['line'] . "\n";
// Здесь можно сохранить промежуточные данные
}
});
set_time_limit(5);
// Бесконечный цикл
while (true) {}
Скрипт был прерван по таймауту после /path/to/script.php:10
Пример 4. Комбинация ignore_user_abort и set_time_limit для фоновых задач
Если скрипт должен продолжать работу даже после того, как клиент разорвал соединение, используйте ignore_user_abort(true) и увеличьте лимит.
ignore_user_abort(true);
set_time_limit(600); // 10 минут
// Длительная обработка, клиент может закрыть страницу
$fp = fopen('/tmp/large_log.txt', 'a');
for ($i = 0; $i < 1000000; $i++) {
fwrite($fp, "Строка $i\n");
}
fclose($fp);
echo "Запись завершена";
(клиент может не увидеть вывод, но файл будет записан полностью)
Пример 5. Изменение таймаута через .user.ini (для PHP-FPM)
На хостингах с PHP-FPM можно создать файл .user.ini в корневой директории сайта, чтобы применить настройки для всех скриптов в этой папке.
; .user.ini
max_execution_time = 200
Файл считывается автоматически при каждом запросе, перезагрузка сервера не требуется. Действует аналогично php.ini, но на уровне директории.
Пример 6. Проверка текущего лимита и изменений через ini_get
echo "Текущий лимит: " . ini_get('max_execution_time') . " секунд\n";
ini_set('max_execution_time', 90);
echo "Новый лимит: " . ini_get('max_execution_time') . " секунд\n";
Текущий лимит: 30 секунд Новый лимит: 90 секунд
Пример 7. Настройка таймаута через консольный PHP (CLI)
В командной строке лимит выполнения обычно неограничен, но его тоже можно переопределить через аргументы или в коде.
php -d max_execution_time=120 script.php
Внутри скрипта также можно использовать set_time_limit().