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

Crontab 執行 PHP 腳本失敗完整排查指南:權限、路徑、環境變數三大核心

     編輯:PHP 綜合知識

前言:定時任務為什麼總是「不跑」?

Crontab 是 Linux 系統級排程器,但 PHP 腳本在 Web 環境正常、放入 crontab 卻靜默失效,是運維高頻痛點。本文系統梳理 **權限、路徑、環境變數** 三大核心成因,提供標準化排查流程與最佳實踐模板。

快速排查清單(按優先級)

  1. 執行權限:腳本檔案是否有 `x` 權限?Shebang 是否正確?
  2. 絕對路徑:crontab 中 PHP 二進制、腳本路徑、include/require 路徑是否全為絕對路徑?
  3. 環境變數:PATH、HOME、LD_LIBRARY_PATH、自定義變數是否缺失?
  4. 輸出導向:標準輸出/錯誤輸出是否重導向至日誌檔?
  5. 執行上下文:是否依賴 `$_SERVER`、`$_ENV`、`$_GET` 等 Web 專有變數?

核心問題深度解析與解決

1. 執行權限與 Shebang

# 檢查權限
ls -la /path/to/script.php
# -rwxr-xr-x 1 user group 1234 Jan 1 00:00 script.php  ✅ 有 x 權限
# -rw-r--r-- 1 user group 1234 Jan 1 00:00 script.php  ❌ 缺少 x 權限

# 添加執行權限
chmod +x /path/to/script.php

# 檢查 Shebang (第一行必須是)
head -1 /path/to/script.php
# #!/usr/bin/env php  ✅ 推薦:自動尋找 php
# #!/usr/local/php/bin/php  ✅ 可行但硬編碼路徑

2. 絕對路徑陷阱(最常見)

錯誤範例:

# crontab -e
* * * * * php script.php                    # ❌ php 不在 PATH,script.php 相對路徑
* * * * * /usr/bin/php script.php           # ❌ script.php 相對路徑,cwd 不一定是腳本目錄

正確範例:

# 方式一:cd 進入目錄再執行(推薦)
* * * * * cd /var/www/project && /usr/local/php/bin/php script.php >> /var/log/cron_script.log 2>&1

# 方式二:全絕對路徑
* * * * * /usr/local/php/bin/php /var/www/project/script.php >> /var/log/cron_script.log 2>&1

PHP 內部 include/require 也必須用絕對路徑:

// ❌ 相對路徑,cron 執行時 cwd 不確定
require_once '../config.php';
require_once './lib/db.php';

// ✅ 使用 __DIR__ 魔術常數
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/lib/db.php';

// ✅ 或定義專案根目錄常數(入口檔案)
define('APP_ROOT', __DIR__ . '/..');
require_once APP_ROOT . '/config.php';

3. 環境變數缺失

Cron 執行環境極度精簡,常見缺失:

完整 crontab 範本

# 環境變數定義(放在 crontab 最前面)
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/php/bin
HOME=/home/wwwuser
LD_LIBRARY_PATH=/usr/local/lib:/usr/lib
APP_ENV=production

# 日誌目錄確保存在
# * * * * * mkdir -p /var/log/cron

# 任務定義
# 每分鐘執行一次(測試用)
* * * * * cd /var/www/project && /usr/local/php/bin/php artisan schedule:run >> /var/log/cron_schedule.log 2>&1

# 每天凌晨 2:30 備份資料庫
30 2 * * * cd /var/www/project && /usr/local/php/bin/php script/backup_db.php >> /var/log/cron_backup.log 2>&1

# 每小時清理快取
0 * * * * cd /var/www/project && /usr/local/php/bin/php script/clear_cache.php >> /var/log/cron_cache.log 2>&1

4. 依賴 Web 專有超全域變數

問題代碼:

// ❌ Cron 環境下不存在
$host = $_SERVER['HTTP_HOST'];
$uri = $_SERVER['REQUEST_URI'];
$ip = $_SERVER['REMOTE_ADDR'];
$docRoot = $_SERVER['DOCUMENT_ROOT'];

解決方案:

// ✅ 使用配置檔或環境變數
$host = getenv('APP_HOST') ?: 'cli.local';
$baseUrl = getenv('APP_BASE_URL') ?: 'https://cli.local';
$docRoot = getenv('APP_DOC_ROOT') ?: __DIR__ . '/../public';

// ✅ 或判斷 SAPI 分流
if (php_sapi_name() === 'cli') {
    // CLI 專用配置
    $config = require __DIR__ . '/config/cli.php';
} else {
    // Web 專用配置
    $config = require __DIR__ . '/config/web.php';
}

調試與驗證技巧

1. 手動模擬 Cron 環境執行

# 切換到執行用戶(通常是 www-data、nginx、wwwuser)
sudo -u wwwuser -H /bin/bash -c "cd /var/www/project && /usr/local/php/bin/php script.php"

# 或直接用 root 測試(注意權限差異)
cd /var/www/project && /usr/local/php/bin/php script.php

2. 捕獲錯誤輸出

# 2>&1 將 stderr 合併到 stdout,統一寫入日誌
* * * * * /usr/bin/php /path/script.php >> /var/log/script.log 2>&1

# 分離輸出
* * * * * /usr/bin/php /path/script.php >> /var/log/script_out.log 2>> /var/log/script_err.log

3. 在腳本內記錄執行軌跡



4. 驗證 Crontab 服務狀態

systemctl status cron      # systemd 系統
service cron status        # SysVinit 系統
crontab -l                 # 查看當前用戶任務
crontab -u wwwuser -l      # 查看指定用戶任務(需 root)

進階:系統級定時器替代方案

變數影響解決
PATH系統命令 (mysqldump, git, composer) 找不到crontab 開頭定義 `PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/php/bin`
HOMEComposer、SSH 金鑰、~/.bashrc 失效設定 `HOME=/home/wwwuser`
LD_LIBRARY_PATHPHP 擴展依賴的共享庫找不到 (如 libxml2, openssl)設定 `LD_LIBRARY_PATH=/usr/local/lib:/usr/lib`
自定義變數應用讀取 `getenv('DB_PASSWORD')` 失敗crontab 定義或腳本內 `putenv()`
方案優點缺點適用場景
systemd Timer精確到秒、支援依賴、日誌整合、隨機延遲配置較複雜、需 root生產環境核心任務
Supervisor + 長運行腳本進程管理、自動重啟、日誌輪轉需額外元件隊列消費者、WebSocket 服務
Laravel Scheduler / Symfony SchedulerPHP 定義排程、可測試、避免重疊框架綁定框架專案
Jenkins / GitLab CI 排程可視化、歷史記錄、通知整合較重、延遲較大部署、構建、報表任務

結語

Crontab 執行 PHP 失敗 90% 歸因於 **路徑不絕對、環境變數缺失、權限不足**。建立標準化部署模板、強制絕對路徑、完善日誌記錄,能徹底消除此類問題。現代專案建議遷移至 systemd Timer 或框架內建調度器,獲得更好的可觀測性與維護性。

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