Запуск PHP сценариев по расписанию через cron
Запуск PHP через cron
Эффективный и надёжный способ запуска PHP-скриптов в cron - использование PHP CLI напрямую, без участия веб-сервера. Такой подход исключает зависимость от HTTP, снижает нагрузку и даёт полный контроль над окружением.
Основная команда cron
* * * * * /usr/bin/php /var/www/project/cron.php >> /var/log/cron.log 2>&1запуск php cron (запуск cron-задач в php)
Пояснение элементов:
- /usr/bin/php - путь к исполняемому файлу PHP CLI. Узнать его можно командой
which phpилиwhereis php. - /var/www/project/cron.php - полный путь к скрипту.
- >> /var/log/cron.log - перенаправление стандартного вывода (stdout) в лог-файл с добавлением.
- 2>&1 - перенаправление стандартного потока ошибок (stderr) туда же.
Типичные ошибки и их решение:
- Путь к PHP может отличаться (например, /usr/local/bin/php). Проверьте командой
which phpот того же пользователя, который будет выполнять задачу. - Скрипт может не находить свои включаемые файлы. Рекомендуется в начале скрипта выполнять
chdir(__DIR__);или использовать абсолютные пути. - Ошибки не видны без перенаправления stderr. Всегда добавляйте
2>&1или отдельный лог ошибок.
Как запускать PHP-скрипт через cron, используя только веб-сервер?
Когда прямой доступ к CLI отсутствует, применяют вызов скрипта через HTTP с помощью wget или curl. Этот метод подходит для скриптов, которые должны обрабатывать HTTP-запросы (например, API), но он менее надёжен из-за возможных тайм-аутов и зависимости от веб-сервера.
* * * * * wget -q -O /dev/null http://localhost/cron.php?key=secret
Флаги: -q (quiet) подавляет вывод, -O /dev/null отправляет ответ в «никуда». Вместо wget можно использовать curl: curl -s -o /dev/null http://localhost/cron.php.
Проблемы:
- Скрипт выполняется под пользователем веб-сервера (www-data), может не иметь прав на запись в нужные директории.
- Выполнение может прерваться по тайм-ауту (обычно 30 секунд). Для длительных задач укажите
set_time_limit(0)в скрипте. - URL не должен быть доступен извне. Используйте локальный адрес (127.0.0.1/localhost) и ключ для проверки.
Как упростить команду cron, если скрипт использует относительные пути?
Если скрипт обращается к файлам относительно своей директории, можно сначала сменить директорию, а затем запустить его через php -f.
* * * * * cd /var/www/project && /usr/bin/php -f cron.php >> /tmp/cron.log 2>&1
Оператор && гарантирует выполнение php только при успешном переходе в директорию. Команда php -f обрабатывает файл как обычный скрипт.
- Если директория изменится (например, при обновлении проекта), cron перестанет работать. Храните команду вместе с кодом.
- Не забывайте про права на выполнение для
cd- необходимо иметь доступ к родительским каталогам.
Как сделать PHP-скрипт исполняемым и вызывать его без явного указания php?
Добавьте шебанг (shebang) в начало файла и установите права на выполнение. После этого cron может запускать скрипт как обычную программу.
#!/usr/bin/php
<?php
// код скрипта
Затем выполните: chmod +x /var/www/project/cron.php. В crontab пишите:
* * * * * /var/www/project/cron.php >> /var/log/cron.log 2>&1
- Убедитесь, что путь в шебанге правильный. Разные версии PHP могут находиться по разным адресам.
- Если файл планируется также вызывать через веб-сервер, шебанг не повлияет на его работу (он будет проигнорирован).
Как управлять несколькими задачами из одного cron-вызова?
Создайте PHP-менеджер, который внутри с помощью shell_exec или exec запускает конкретные скрипты. Это удобно, когда нужно выполнять разные задачи, но с одинаковым логгированием или блокировками.
#!/usr/bin/php
<?php
$tasks = [
'backup' => '/var/www/project/backup.php',
'cleanup' => '/var/www/project/cleanup.php',
];
foreach ($tasks as $name => $script) {
$output = shell_exec("/usr/bin/php $script 2>&1");
file_put_contents("/var/log/cron_$name.log", $output, FILE_APPEND);
}
- Скрипты могут выполняться последовательно, что увеличивает общее время. Для параллельности используйте фоновый запуск с
&илиpcntl_fork. - Не забывайте про ресурсы: если один скрипт зависнет, остальные не запустятся до его завершения.
Расширенные примеры
1. Предотвращение повторного запуска (блокировка)
Чтобы один и тот же скрипт не выполнялся одновременно (например, при долгой задаче), используйте файловую блокировку:
<?php
$lockFile = '/tmp/cron_job.lock';
$fp = fopen($lockFile, 'w+');
if (!flock($fp, LOCK_EX | LOCK_NB)) {
exit("Script already running\n");
}
// основная задача
sleep(30); // имитация работы
echo "Task completed\n";
flock($fp, LOCK_UN);
fclose($fp);
Результат при повторном запуске до завершения первого:
Script already running
Пояснение: Флаг LOCK_NB делает попытку блокировки неблокирующей. Если блокировка уже установлена, скрипт завершается с сообщением.
2. Логирование с разными уровнями и ротация
Для детального логирования ошибок и успешного выполнения используйте класс-логгер. Пример записи в файл с разделением по важности:
<?php
function logMessage($level, $message) {
$file = '/var/log/cron_app.log';
$date = date('Y-m-d H:i:s');
$line = "[$date] [$level] $message\n";
file_put_contents($file, $line, FILE_APPEND | LOCK_EX);
}
try {
// выполнение задачи
logMessage('INFO', 'Task started');
// ... код ...
logMessage('INFO', 'Task finished successfully');
} catch (Exception $e) {
logMessage('ERROR', $e->getMessage());
}
В cron команда может быть расширена для ротации логов (например, с помощью cronolog) или перенаправления в syslog.
3. Передача параметров через cron и их обработка
В crontab можно передавать аргументы после имени скрипта. Обработка внутри PHP через getopt:
# crontab запись
*/5 * * * * /usr/bin/php /var/www/project/report.php --type=weekly --format=csv >> /tmp/report.log 2>&1
<?php
$options = getopt('', ['type:', 'format:']);
$type = $options['type'] ?? 'daily';
$format = $options['format'] ?? 'html';
echo "Generating $format report for $type\n";
// генерация отчёта
Результат:
Generating csv report for weekly
Этот подход позволяет использовать один и тот же скрипт для разных задач, настраивая его через cron.
4. Запуск скрипта с нестандартной версией PHP
Если в системе установлено несколько версий PHP, явно указывайте нужную. Также можно подгрузить свой php.ini:
30 2 * * * /usr/local/php7.4/bin/php -c /etc/php74/custom.ini /var/www/project/script.php
Флаг -c указывает путь к конфигурационному файлу. Это полезно, когда требуется определённое расширение или увеличенный лимит памяти.
- Убедитесь, что путь к PHP корректен и версия CLI установлена.
- Разные версии могут использовать разные директории для расширений.