首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Linux Crontab 定時執行 PHP 腳本完整指南:環境變數、鎖機制、日誌、監控與避坑

     編輯:PHP 相關知識

Crontab 是 Linux 定時任務標準工具,但 PHP CLI 執行環境與 Web (FPM) 差異極大,導致「手動跑通、排程失敗」是常見痛點。本文系統整理 Crontab 語法、PHP CLI 環境配置、併發防重鎖、日誌輸出、監控告警與常見坑點清單。

Crontab 基本語法

* * * * *  執行命令
- - - - -
| | | └─ 週幾 (0-7) (Sun=0 or 7)
| | └──── 月份 (1-12)
| └────── 日期 (1-31)
| └────── 小時 (0-23)
└──────── 分鐘 (0-59)

特殊符號:
*  所有值
,  列舉 (1,15,30)
-  範圍 (1-5)
/  步長 (*/10 = 每 10 分鐘)
@yearly @monthly @weekly @daily @hourly @reboot

標準排程範例

# 每天凌晨 2:30 執行備份
30 2 * * * /usr/bin/php /var/www/scripts/backup.php >> /var/log/backup.log 2>&1

# 每小時第 5 分鐘清理快取
5 * * * * /usr/bin/php /var/www/scripts/clear_cache.php

# 每週一 03:00 產生報表 (僅工作日)
0 3 * * 1-5 /usr/bin/php /var/www/scripts/report.php

# 開機自動啟動佇列 Worker
@reboot /usr/bin/php /var/www/artisan queue:work --sleep=3 --tries=3 >> /var/log/queue.log 2>&1

關鍵環境變數配置 (解決 90% 失敗原因)

# 在 crontab 檔案開頭定義 (crontab -e)
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
# PHP 專用環境變數
PHP_INI_SCAN_DIR=/etc/php.d
APP_ENV=production
# 專案根目錄 (供腳本定位 .env、vendor)
APP_BASE=/var/www/html

# 然後寫任務
30 2 * * * cd /var/www/html && /usr/bin/php artisan backup:run --env=production >> /var/log/backup.log 2>&1

併發防重鎖 (避免任務重疊執行)

<?php
// scripts/backup.php
require __DIR__ . '/../vendor/autoload.php';

$lockFile = sys_get_temp_dir() . '/backup_' . basename(__FILE__, '.php') . '.lock';
$fp = fopen($lockFile, 'c+');

if (!flock($fp, LOCK_EX | LOCK_NB)) {
    // 已有實例在執行
    error_log("[$lockFile] Another instance is running, exit.");
    exit(0);
}

// 註冊釋放鎖 (腳本結束自動釋放,但顯式釋放更佳)
register_shutdown_function(function() use ($fp, $lockFile) {
    flock($fp, LOCK_UN);
    fclose($fp);
    @unlink($lockFile);
});

// 實際業務邏輯
// ...
echo "Backup completed at " . date('c') . "\n";

進階:使用 flock 獨佔執行包裝器

# /usr/local/bin/php-cron-wrapper
#!/bin/bash
# 用法:php-cron-wrapper "lock_name" "php_script.php" [args...]

LOCK_NAME=$1
shift
SCRIPT=$1
shift

LOCK_FILE="/var/lock/php-cron-${LOCK_NAME}.lock"
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
    echo "[$(date)] Lock $LOCK_NAME held, skipping." >&2
    exit 0
fi

# 執行 PHP 腳本,保留所有參數
exec php "$SCRIPT" "$@"
# crontab 使用
30 2 * * * /usr/local/bin/php-cron-wrapper backup /var/www/html/artisan backup:run >> /var/log/backup.log 2>&1

日誌與監控最佳實踐

需求方案
標準輸出/錯誤捕獲>> /var/log/xxx.log 2>&1 (追加模式)
系統日誌整合logger -t backup "message" 或 Monolog SyslogHandler
執行時間記錄腳本開頭 $start = microtime(true); 結尾 error_log("Duration: " . (microtime(true) - $start));
失敗告警腳本非零退出碼觸發監控系統 (Prometheus Node Exporter textfile, Zabbix, Datadog)
健康檢查端點定時任務完成後 curl 回報健康檢查服務 (Healthchecks.io, Cronitor)

常見坑點清單

  1. PHP 版本不一致:which php vs php -v,crontab 用絕對路徑 /usr/bin/php 或 /usr/local/bin/php。
  2. 工作目錄錯誤:相對路徑 require '../config.php' 失效。解法:cd /var/www/html && php script.php 或腳本內 chdir(__DIR__)。
  3. 環境變數缺失:$_ENV、getenv() 讀不到 .env。解法:crontab 定義或腳本 Dotenv::load() 指定路徑。
  4. 權限不足:寫入日誌、快取、上傳目錄失敗。解法:以正確用戶執行 (crontab -u www-data -e) 或設定目錄權限。
  5. 記憶體/執行時間限制:CLI php.ini 可能與 FPM 不同。解法:php -d memory_limit=512M -d max_execution_time=0 script.php。
  6. 時區錯誤:date() 輸出非預期時區。解法:date_default_timezone_set('Asia/Taipei') 或 php.ini date.timezone。
  7. 編碼問題:中文亂碼。解法:確保終端機 Locale 為 UTF-8 (export LANG=zh_TW.UTF-8)。

系統級替代方案

  • systemd timers:更精確、支援依賴、日誌整合 journald、可啟用 Persistent=yes 彌補關機錯過執行。
  • Supervisor / systemd service:長期運行 Worker (Queue、WebSocket) 優於 Crontab 輪詢。
  • Kubernetes CronJob:容器化環境原生支援。

掌握「絕對路徑、環境變數、工作目錄、防重鎖、日誌輸出」五大鐵律,並建立標準化包裝器 php-cron-wrapper,能讓 PHP 定時任務在生產環境穩定、可觀測、可維護運行。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved