在 PHP 應用中動態管理 Linux Crontab 任務(新增、修改、刪除、查看)是自動化運維的常見需求。本文介紹兩種主流方案:本機執行 php-crontab-manager 庫(PHP 5.3+)、遠程 SSH2 操作 Ssh2_crontab_manager 類,並涵蓋安裝、API 使用、權限控制與安全最佳實踐。
composer require mediovski/php-crontab-manager
需 PHP ≥ 5.3,執行 PHP 的用戶需擁有 crontab 指令權限(通常為 www-data 或對應 FPM 用戶)。
use Mediovski\Crontab\CrontabManager;
$crontab = new CrontabManager();
// 載入現有 crontab(指定檔案或自動讀取當前用戶)
$crontab->enableOrUpdate('/tmp/my/crontab.txt'); // 或 $crontab->load();
// 新增任務
$job = $crontab->newJob();
$job->on('* * * * *') // 每分鐘
->doJob('/usr/bin/php /var/www/artisan schedule:run');
$crontab->add($job);
// 批次新增(鏈式)
$job->onMinute('20-30')->doJob("echo 'foo'");
$crontab->add($job);
$job->onMinute('35-40')->doJob("echo 'bar'");
$crontab->add($job);
// 移除任務(支援正則)
$crontab->removeJob('/echo foo/');
// 儲存寫入系統 crontab
$crontab->save();
// 取得所有任務陣列
$jobs = $crontab->getJobs();
| 方法 | 說明 | 範例 |
|---|---|---|
on($cronExpr) | 完整 cron 表達式 | on('0 2 * * *') 每天 02:00 |
everyMinute() | 每分鐘 | |
everyHour() | 每小時 | |
daily($time) | 每天指定時間 | daily('14:30') |
weekly($day, $time) | 每週 | weekly(1, '09:00') 週一 09:00 |
monthly($date, $time) | 每月 | monthly(1, '00:00') 每月 1 號 |
適用於跳板機/管理後台集中管理多台伺服器的 crontab。
ssh2 擴展:pecl install ssh2-1.3.1(需 libssh2-devel)crontab 權限<?php
class Ssh2CrontabManager {
private $conn;
private string $remoteFile = '/tmp/crontab_backup.txt';
public function __construct(string $host, int $port, string $user, string $pass) {
$this->conn = ssh2_connect($host, $port);
if (!$this->conn) throw new Exception("SSH 連線失敗");
if (!ssh2_auth_password($this->conn, $user, $pass)) throw new Exception("認證失敗");
}
// 執行遠程指令
private function exec(string $cmd): string {
$stream = ssh2_exec($this->conn, $cmd);
stream_set_blocking($stream, true);
return stream_get_contents($stream);
}
// 同步遠程 crontab 到本地暫存檔
public function sync(): self {
$this->exec("crontab -l > {$this->remoteFile} 2>/dev/null || > {$this->remoteFile}");
return $this;
}
// 新增任務
public function addJob(string $schedule, string $command): self {
$line = "{$schedule} {$command}";
$this->exec("echo '{$line}' >> {$this->remoteFile}");
return $this;
}
// 移除任務(正則匹配)
public function removeJob(string $pattern): self {
$this->exec("grep -v -E '{$pattern}' {$this->remoteFile} > {$this->remoteFile}.new && mv {$this->remoteFile}.new {$this->remoteFile}");
return $this;
}
// 寫回遠程 crontab
public function save(): bool {
$result = $this->exec("crontab {$this->remoteFile}");
$this->exec("rm -f {$this->remoteFile} {$this->remoteFile}.new");
return strpos($result, 'error') === false;
}
// 取得當前任務列表
public function listJobs(): array {
$output = $this->exec("cat {$this->remoteFile}");
return array_filter(explode("\n", trim($output)));
}
}
// 使用範例
$mgr = new Ssh2CrontabManager('192.168.1.10', 22, 'deploy', 'secret');
$mgr->sync()
->addJob('0 3 * * *', '/usr/bin/php /var/www/backup.php')
->addJob('*/10 * * * *', '/usr/bin/php /var/www/healthcheck.php')
->save();
cronmgr),僅授予 crontab 權限,/etc/sudoers 限制 NOPASSWD: /usr/bin/crontab。removeJob 再 addJob,避免重複任務。save() 前自動備份 crontab -l > /backup/crontab_$(date +%F).bak。| 現象 | 原因 | 解決 |
|---|---|---|
| save() 後任務未生效 | PHP-FPM 用戶無 crontab 權限 | 將用戶加入 crontab 群組或 sudoers |
| SSH2 連線逾時 | 防火牆/SELinux/SSH 配置 | 檢查 22 port、允許 PasswordAuthentication |
| 特殊字元導致指令失效 | 未轉義 $、%、反引號等 | 使用 escapeshellarg() 包裹指令參數 |
| 環境變數缺失(如 PATH) | crontab 執行環境極簡 | 指令前加 PATH=/usr/local/bin:/usr/bin && 或腳本內完整路徑 |
PHP 管理 Crontab 透過 php-crontab-manager 可快速落地本機自動化;跨伺服器場景結合 SSH2 實現集中式管控。核心在於權限隔離、輸入驗證與操作審計。建議將管理介面整合至內部運維平台,搭配 GitOps 流程(crontab 定義存儲於 Git、CI/CD 自動同步),實現基礎設施即代碼。