Запуск PHP сценариев по расписанию через cron

Раздел: Администрирование 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 установлена.
  • Разные версии могут использовать разные директории для расширений.

Запуск cron-задач в PHP - comments

En
запуск php cron (php)