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

PHP 定時任務實現全方案詳解:從 Crontab 到用戶觸發、第三方跳板

     編輯:PHP 綜合知識

前言

PHP 本身無多線程、無原生定時器,所有定時任務都需借助外部機制。本文系統梳理四大類實現方案:系統級 Crontab(最高效)、Windows 計劃任務、用戶訪問觸發(虛擬主機適用)、第三方平台跳板,並深度剖析各方案的原理、代碼實現、優劣勢與適用場景。

方案一:Linux Crontab + PHP CLI(生產環境首選)

核心原理

繞過 Web 服務器(Nginx/Apache),直接調用 PHP 解析器執行腳本,效率最高、資源佔用最低。

操作步驟

  1. crontab -e 編輯定時任務表
  2. 按格式添加任務:分 時 日 月 周 命令
  3. 命令格式:/usr/local/bin/php /path/to/script.php

實戰示例

# 每 2 小時執行一次
00 */2 * * * /usr/local/bin/php /home/www/script.php

# 每天凌晨 3:30 執行
30 3 * * * /usr/local/bin/php /home/www/daily_job.php >> /home/www/logs/daily.log 2>&1

# 每分鐘檢查一次(高頻任務慎用)
* * * * * /usr/local/bin/php /home/www/check.php

關鍵優勢

  • 無 Web 服務器開銷,無超時限制(默認 CLI 無 max_execution_time)
  • 支持長時間運行腳本、大內存操作
  • 系統級可靠性,開機自啟,不依賴用戶訪問

方案二:Windows 計劃任務 + BAT 腳本

實現步驟

  1. 創建 cron.bat:
    D:\php\php.exe -q D:\website\test.php
  2. 控制面板 → 管理工具 → 任務計劃 → 創建基本任務
  3. 設置觸發器(每日/每週/每月/單次),動作選擇「啟動程序」,選中 cron.bat

注意事項

  • 路徑不可包含空格,或用雙引號包裹
  • PHP 設置 php.ini 中 extension_dir 為絕對路徑
  • 權限問題:以最高權限運行、指定賬戶登錄

方案三:虛擬主機環境下的用戶觸發機制(無 Crontab 權限時的救星)

核心難點

  • PHP 腳本默認 30 秒超時(max_execution_time)
  • 用戶關閉瀏覽器導致腳本中斷
  • 長時間 sleep 佔用進程槽,極易耗盡 FPM 進程數

技術棧組合拳

// 1. 忽略用戶斷開
ignore_user_abort(true);
// 2. 移除執行時間限制
set_time_limit(0);
// 3. 防重複執行鎖(文件鎖)
$lockFile = __DIR__ . '/cron.lock';
if (file_exists($lockFile) && (time() - filemtime($lockFile) < 3600)) exit();
// 4. 異步觸發核心:fsockopen 非阻塞請求
function async_request($url) {
    $parsed = parse_url($url);
    $host = $parsed['host'];
    $port = $parsed['port'] ?? ($parsed['scheme'] === 'https' ? 443 : 80);
    $path = $parsed['path'] . ($parsed['query'] ? '?' . $parsed['query'] : '');
    $fp = fsockopen(($parsed['scheme'] === 'https' ? 'ssl://' : '') . $host, $port, $errno, $errstr, 1);
    if (!$fp) return false;
    stream_set_timeout($fp, 1);
    $header = "GET $path HTTP/1.1\r\nHost: $host\r\nConnection: Close\r\n\r\n";
    fwrite($fp, $header);
    usleep(1000); // 關鍵:確保請求發出
    fclose($fp);
    return true;
}

三種觸發模式對比

模式原理優點缺點適用場景
死循環 + sleep腳本常駐內存,定時喚醒實時性強佔用進程、易崩潰、虛擬主機禁用極少見,不推薦
用戶訪問掃描任務表每次請求檢查是否有到期任務無額外資源、實現簡單執行時間不確定(依賴訪問量)、可能延遲低頻、非實時任務(如緩存清理、統計更新)
第三方跳板阿里云/百度云/監控服務定時回調時間精準、不佔用自身資源依賴第三方、需公網可訪問虛擬主機、無服務器權限環境

用戶觸發模式完整實現(任務表版)

// tasks.json 任務表
[
    {"name": "clean_cache", "url": "https://site.com/cron/clean_cache", "cron": "0 3 * * *"},
    {"name": "daily_report", "url": "https://site.com/cron/daily_report", "cron": "30 3 * * *"}
]

// common.php 每次請求掛載
function check_cron_tasks() {
    $tasks = json_decode(file_get_contents('tasks.json'), true);
    $now = time();
    foreach ($tasks as $k => $task) {
        // 簡易 cron 表達式匹配(生產環境建議用 dragonmantank/cron-expression)
        if (cron_match($task['cron'], $now)) {
            $lastRun = get_last_run($task['name']);
            if ($now - $lastRun >= 60) { // 至少間隔 60 秒防重複
                async_request($task['url']);
                set_last_run($task['name'], $now);
            }
        }
    }
}

// 入口文件首行調用
check_cron_tasks();

方案四:第三方平台跳板(零成本、高可靠)

主流免費平台

  • 阿里云函數計算/定時觸發器:每天免費 100 萬次調用,支持 HTTP 觸發
  • 騰訊云雲函數:類似,支持 Cron 表達式
  • GitHub Actions:on: schedule 定時運行 workflow,可 curl 回調
  • UptimeRobot / 搶站監控:每 5 分鐘 HTTP 請求,可作為高頻觸發器
  • OneIndex / 云函數部署:自建跳板服務

跳板腳本模板

// jumper.php 部署在有定時能力的平台
$targets = [
    'https://mysite.com/cron/job1',
    'https://mysite.com/cron/job2',
];
foreach ($targets as $url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_TIMEOUT => 3,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_SSL_VERIFYPEER => false,
    ]);
    curl_exec($ch);
    curl_close($ch);
}

方案選型決策樹

  1. 有服務器 Root 權限(Linux) → Crontab + PHP CLI(最優)
  2. Windows 服務器 → 計劃任務 + BAT
  3. 虛擬主機/無服務器權限,任務非實時 → 用戶訪問觸發 + 任務表
  4. 虛擬主機,需精準定時 → 第三方平台跳板(GitHub Actions / 云函數)
  5. 高併發、長耗時、需監控 → Swoole / Workerman 常駐進程 + 內置 Timer(進階)

進階方案:Swoole 內置毫秒級定時器

// server.php
$server = new Swoole\Server('0.0.0.0', 9501);
$server->set(['worker_num' => 1, 'task_worker_num' => 4]);

$server->on('WorkerStart', function ($server, $workerId) {
    if ($workerId === 0) {
        // 每天 03:00 執行
        $server->tick(86400000, function () use ($server) {
            if (date('H:i') === '03:00') {
                $server->task('daily_job');
            }
        });
        // 每分鐘檢查
        $server->tick(60000, function () use ($server) {
            $server->task('minute_check');
        });
    }
});

$server->on('Task', function ($server, $taskId, $workerId, $data) {
    if ($data === 'daily_job') { /* ... */ }
    if ($data === 'minute_check') { /* ... */ }
});

$server->start();

總結與最佳實踐

  • 首選系統級 Crontab:穩定、高效、無依賴
  • 虛擬主機用戶觸發:務必用 fsockopen 異步觸發,避免阻塞用戶請求
  • 任務冪等性:所有定時任務必須設計為可重複安全執行
  • 日誌與監控:記錄執行時間、耗時、結果,配合告警
  • 避免 sleep 長佔用:FPM 模式下 sleep 會佔用進程槽,極易導致 502
  • 鎖機制防重複:文件鎖、Redis SETNX、數據庫唯一索引

根據業務場景、基礎設施權限、實時性要求,選擇最適合的方案。現代雲原生架構下,雲函數 + 定時觸發器正成為虛擬主機/Serverless 環境的最佳實踐。

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