專案根目錄 /
├── framework/ # Yii 框架核心
├── protected/
│ ├── commands/
│ │ ├── cron.php # 入口腳本
│ │ └── ShellCommand.php # 實際命令類別
│ ├── config/
│ │ ├── console.php # Console 專用設定
│ │ └── main.php # Web 共用設定
│ └── ...
└── public/
└── index.php
protected/commands/cron.php
<?php
// 修改為實際框架路徑
$yii = dirname(__FILE__) . '/../../framework/yii.php';
require_once($yii);
$configFile = dirname(__FILE__) . '/../config/console.php';
Yii::createConsoleApplication($configFile)->run();
protected/config/console.php
<?php
return [
'basePath' => dirname(__FILE__) . DIRECTORY_SEPARATOR . '..',
'name' => 'Console App',
// 預載入模型、元件、擴充套件
'import' => [
'application.models.*',
'application.components.*',
'application.extensions.*',
],
'components' => [
// Log 設定:寫入檔案而非網頁
'log' => [
'class' => 'CLogRouter',
'routes' => [
[
'class' => 'CFileLogRoute',
'levels' => 'info, warning, error',
'logFile' => 'console.log',
],
],
],
// 資料庫連線 (可與 Web 共用或獨立)
'db' => [
'class' => 'CDbConnection',
'connectionString' => 'mysql:host=localhost;dbname=myapp',
'username' => 'user',
'password' => 'pass',
'charset' => 'utf8',
'tablePrefix' => 'tbl_',
'emulatePrepare' => true,
],
// 如需快取、郵件等元件亦可在此設定
],
'params' => require('params.php'),
];
protected/commands/ShellCommand.php
<?php
class ShellCommand extends CConsoleCommand
{
// 定義動作:php cron.php shell sendReport
public function actionSendReport($args = [])
{
$this->stdout("開始發送日報...\n");
// 使用模型、元件如同 Web 環境
$users = User::model()->findAll('status=1');
foreach ($users as $user) {
// 發送邏輯...
$this->stdout("處理用戶: {$user->email}\n");
}
$this->stdout("日報發送完成\n");
return 0; // 正常結束代碼
}
// 另一個動作:php cron.php shell cleanup
public function actionCleanup($days = 30)
{
$this->stdout("清理 {$days} 天前的暫存資料...\n");
$count = TempFile::model()->deleteAll('created_at < :date', [
':date' => date('Y-m-d', strtotime("-{$days} days"))
]);
$this->stdout("已刪除 {$count} 筆\n");
return 0;
}
// 覆寫 getHelp() 提供說明
public function getHelp()
{
return << [params]
可用動作:
sendReport 發送每日報表
cleanup [days] 清理暫存檔 (預設 30 天)
HELP;
}
}
Yii 1.x 會自動掃描 protected/commands/ 下的 *Command.php,類別名稱對應命令名稱:
ShellCommand → shellBackupCommand → backup# 編輯 crontab
crontab -e
# 範例:每天凌晨 2:30 執行日報發送
30 2 * * * /usr/bin/php /var/www/project/protected/commands/cron.php shell sendReport >> /var/log/cron_sendReport.log 2>&1
# 每小時清理暫存
0 * * * * /usr/bin/php /var/www/project/protected/commands/cron.php shell cleanup 7 >> /var/log/cron_cleanup.log 2>&1
# 每週日 3:00 備份資料庫
0 3 * * 0 /usr/bin/php /var/www/project/protected/commands/cron.php backup >> /var/log/cron_backup.log 2>&1
| 項目 | 說明 |
|---|---|
| PHP CLI 版本 | 確保 /usr/bin/php 為正確版本 (可用 php -v 驗證) |
| 環境變數 | CLI 不載入 Web 環境變數,需在 console.php 完整設定 DB、路徑等 |
| 執行權限 | cron 執行者需有專案目錄讀取權限、log 寫入權限 |
| 記憶體限制 | CLI 獨立 php.ini,大量資料處理請調整 memory_limit |
| 避免重複執行 | 長時間任務加鎖 (flock/Redis lock) 防止重疊 |
| 錯誤通知 | 導向 log 檔,並設定 logrotate;關鍵失敗發送郵件/Slack |
<?php
class ShellCommand extends CConsoleCommand
{
public function actionSendReport()
{
$lockFile = sys_get_temp_dir() . '/cron_sendReport.lock';
$fp = fopen($lockFile, 'w');
if (!flock($fp, LOCK_EX | LOCK_NB)) {
$this->stderr("上一任務尚未結束,跳過本次執行\n");
return 1;
}
try {
// 實際任務邏輯...
} finally {
flock($fp, LOCK_UN);
fclose($fp);
}
return 0;
}
}
?>