CodeIgniter定时任务必须通过CLI入口执行,CI3用index.php+控制器方法调用,CI4必须继承BaseCommand类并用spark运行;crontab需用绝对路径、显式cd、重定向日志,禁用curl/wget触发。

CodeIgniter 定时任务不能靠浏览器访问或直接 php script.php 运行,必须走框架 CLI 入口,否则 is_cli() 判断失败、服务未加载、数据库连不上——这是绝大多数人卡住的第一步。
CI3 怎么写可被 crontab 调用的控制器
CI3 没有 spark 命令,靠 index.php + 控制器方法组合触发。核心是:入口文件必须能识别 CLI 环境,控制器要主动拦截非 CLI 请求。
-
is_cli()函数已内置,但需确保没被覆盖;它依赖PHP_SAPI === 'cli'或defined('STDIN') - 控制器构造函数里加判断:
if (!$this->input->is_cli_request()) { show_error('CLI only'); } - 方法参数通过
$this->uri->segment(3)或$this->input->get()获取(注意:CLI 下$_GET不可用,$argv也不推荐直接用) - 命令行调用格式固定:
/usr/bin/php /path/to/index.php controller_name method_name arg1 arg2 - 示例:每天清理 7 天前上传文件,控制器
Cron.php中写public function clean_temp_files($days = 7),crontab 写成0 2 * * * /usr/bin/php /var/www/myapp/index.php cron clean_temp_files 7
CI4 的 CLI 命令必须继承 BaseCommand 类
CI4 不允许任何“裸脚本”执行,所有 CLI 逻辑必须封装为 app/Commands/xxxCommand.php,否则 spark 根本看不到它,更别说跑起来。
- 类名必须以
Command结尾,比如SendNewsletterCommand;否则spark list不显示 - 必须设置
$this->group和$this->description,否则在spark list里只显示命令名,没说明 - 获取参数统一用
$this->getArgument('name')或$this->getOption('force'),别碰$argv或$_SERVER['argv'] - 输出必须用
$this->info()/$this->error(),echo/print_r 会破坏颜色和换行,且在某些终端下截断 - 别在命令里手动调
Services::router()或触发Events::trigger('post_system'),CLI 下这些服务行为异常,可能报错或静默失败
crontab 里调用失败的 90% 原因是路径和环境变量不对
本地能跑不等于 crontab 能跑。crontab 使用极简 shell 环境,PATH、当前目录、PHP_BINARY 都和你手动执行时不同。
- 绝对路径是铁律:
/usr/bin/php不要写成php,/var/www/myapp/spark不要写成./spark或~/myapp/spark - 工作目录不默认是项目根目录,加
cd /var/www/myapp &&前缀最稳妥,否则APPPATH可能指向/导致配置加载失败 - 确认 PHP CLI 版本和扩展一致:
crontab里执行/usr/bin/php -v和/usr/bin/php -m | grep pdo,和你在终端里敲的一致吗? - 日志重定向必须显式写:
> /var/log/myapp-cron.log 2>&1,否则错误全丢进黑洞,连Class not found都看不到 - 如果用
cron.d文件(如/etc/cron.d/myapp),注意多一列用户名字段:0 3 * * * www-data /usr/bin/php /var/www/myapp/spark backup:db >> /var/log/backup.log 2>&1
别用 curl/wget 访问 URL 触发定时任务
用 curl http://yoursite.com/index.php/cron/daily_backup 看似简单,实则埋雷无数。
- Web 服务器可能限制爬虫或未登录访问,
show_403()或重定向到登录页,任务就静默失败 - 超时风险高:数据库备份耗时长,Nginx/Apache 默认 timeout 是 30–60 秒,容易中断
- Session、CSRF、IP 白名单等中间件会在 CLI 下失效,但在 Web 请求中生效,导致行为不一致
- 每次请求都走完整 HTTP 生命周期(路由、filter、output 缓存),性能开销大,还可能意外触发 log、email、cache 清理等副作用
- 真正需要 Web 触发的场景极少,比如调试阶段临时跑一次,正式环境请一律走 CLI
最易被忽略的点:CI4 的 spark 命令本身是 shell 脚本,它依赖项目根目录下的 vendor/autoload.php 和 app/Config/Paths.php。一旦 crontab 工作目录错位,autoload 就加载失败,报 Class 'Config\Services' not found —— 这不是代码问题,是路径问题,查日志前先确认 cd 是否到位。


















