Windows 任務計劃程序 相當於 Linux `cron`。它在指定時間啟動 `php.exe` 進程,傳入腳文件路徑作為參數執行。PHP 腳本以 **CLI 模式** 運行,無 Web 服務器參與,無超時限制(默認),可訪問完整文件系統。
Win+R → `taskschd.msc` → 回車
或:控制面板 → 系統和安全 → 管理工具 → 任務計劃程序
右側操作欄 → **創建基本任務** → 名稱:`PHP_Backup_DB` → 描述:`每天凌晨 2 點備份 MySQL` → 下一步
| 字段 | 填寫內容 | 說明 |
|---|---|---|
| 程序/腳本 | `C:\php\php.exe` | PHP CLI 可執行文件**完整絕對路徑**,必須帶雙引號若路徑含空格 |
| 添加參數 | `-f "C:\www\scripts\backup_db.php"` | `-f` 指定腳本文件,**路徑含空格必須雙引號** |
| 起始於 | `C:\www\scripts` | 工作目錄,腳本內相對路徑基於此目錄 |
**完整命令行等效**:
"C:\php\php.exe" -f "C:\www\scripts\backup_db.php"
<?php
// backup_db.php
// 1. 設置無限執行時間、內存
set_time_limit(0);
ini_set('memory_limit', '512M');
// 2. 禁用輸出緩衝,實時輸出日誌
while (ob_get_level()) ob_end_clean();
ini_set('implicit_flush', 1);
// 3. 設置工作目錄為腳本所在目錄 (防止相對路徑錯誤)
chdir(dirname(__FILE__));
// 4. 載入配置/自動加載
require_once __DIR__ . '/../vendor/autoload.php';
$config = require __DIR__ . '/../config/db.php';
// 5. 業務邏輯
try {
$pdo = new PDO($config['dsn'], $config['user'], $config['pass']);
$sql = "SELECT * INTO OUTFILE '/backups/users_" . date('Ymd') . ".csv' FIELDS TERMINATED BY ',' FROM users";
$pdo->exec($sql);
echo "[" . date('H:i:s') . "] Backup completed.\n";
} catch (Exception $e) {
error_log("[" . date('H:i:s') . "] Backup failed: " . $e->getMessage());
exit(1); // 非零退出碼,任務計劃可記錄失敗
}
// 6. 退出碼:0=成功,非0=失敗
exit(0);
?>
<?php
// 腳本開頭加入文件鎖
$lockFile = sys_get_temp_dir() . '/backup_db.lock';
$fp = fopen($lockFile, 'c+');
if (!flock($fp, LOCK_EX | LOCK_NB)) {
echo "另一實例正在運行,退出。\n";
exit(0);
}
// 註冊釋放
register_shutdown_function(function() use ($fp, $lockFile) {
flock($fp, LOCK_UN);
fclose($fp);
@unlink($lockFile);
});
?>
$logFile = __DIR__ . '/../logs/backup_' . date('Y-m') . '.log';
$msg = json_encode([
'time' => date('c'),
'script' => basename(__FILE__),
'status' => 'success',
'duration_ms' => (microtime(true) - $start) * 1000,
], JSON_UNESCAPED_UNICODE);
file_put_contents($logFile, $msg . PHP_EOL, FILE_APPEND | LOCK_EX);
"C:\php\php.exe" -f "C:\www\scripts\backup.php" -- --db=users --type=full --compress=gzip
// 腳本內獲取:$options = getopt('', ['db:', 'type:', 'compress:']);
| 現象 | 原因 | 解決 |
|---|---|---|
| 任務歷史顯示「操作啟動失敗 (0x80070005) 拒絕訪問」 | 運行賬號密碼錯誤、或無「登錄為批處理作業」權限 | 重新輸入密碼;`secpol.msc` → 本地策略 → 用戶權限分配 → 登錄為批處理作業 → 添加該用戶 |
| 任務顯示「運行中」但腳本未執行/無輸出 | 「起始於」目錄錯誤、腳本路徑含空格未加引號、PHP 版本不匹配 (x86/x64) | 檢查路徑引號;`php -v` 確認架構;啟用任務歷史記錄查看詳細錯誤 |
| 腳本手動運行正常,計劃任務失敗 | 環境變量不同 (PATH、PHP_INI_SCAN_DIR)、當前工作目錄不同、權限不同 | 腳本內 `chdir(dirname(__FILE__))`;使用絕對路徑;對比 `php -i` 環境變量 |
| 長時間腳本被強制終止 | 任務計劃默認「如果任務運行超過 3 天則停止」 | 常規 → 設置 → 「如果任務運行超過」改為「不限制」或較大值 |
| 中文輸出亂碼 | CMD 默認代碼頁 936 (GBK),PHP 輸出 UTF-8 | 腳本開頭 `system('chcp 65001');` 或輸出前 `iconv('UTF-8','GBK',$msg)` |
| 方案 | 優勢 | 適用場景 |
|---|---|---|
| Linux Cron + SSH | 原生、穩定、日誌豐富 | 生產環境首選,跨平台部署 |
| Jenkins / GitLab CI | 可視化、流水線、參數化、分佈式 | 構建/部署/測試任務 |
| Supervisor + PHP Daemon | 常駐進程、秒級調度、狀態監控 | 高頻任務、隊列消費者 |
| Windows 原生任務計劃 + PowerShell | 無額外依賴、集成系統事件觸發 | 簡單定時、Windows 專用環境 |