必须用宝塔PHP对应版本的绝对路径(如/www/server/php/82/bin/php)执行CLI脚本,选Shell脚本类型并显式cd到项目目录,添加端口或进程判断逻辑防止重复启动。

必须用绝对路径调用宝塔 PHP CLI 二进制文件
直接写 php /path/to/script.php 几乎必然失败——宝塔多 PHP 版本共存,系统 php 命令不指向你站点实际用的版本,扩展、SSL、php.ini 全都不匹配。
正确做法是:先确认你项目绑定的 PHP 版本(比如 PHP 8.2),再找到对应 CLI 路径:/www/server/php/82/bin/php。这个路径可在宝塔「软件商店 → PHP 管理 → PHP 8.2 → 设置 → 配置文件」顶部看到。
所有定时任务命令必须显式写出该完整路径,不能省略。
选 Shell 脚本类型,别碰“PHP 脚本”类型
宝塔面板里那个“PHP 脚本”类型看着方便,但它是阉割版环境:不加载 Composer 自动加载、不继承当前项目工作目录、不读取 .env 或项目级配置,连 file_get_contents('config.php') 都可能因相对路径崩掉。
务必选“Shell 脚本”,并在脚本内容里写成:/www/server/php/82/bin/php /www/wwwroot/example.com/cli.php >> /www/wwwroot/example.com/runtime/cron.log 2>&1
这样才走真实 CLI 环境,且能捕获全部错误输出到日志。
脚本开头加 #!/bin/bash 并显式切换工作目录
宝塔计划任务默认用 sh 执行,不加载 ~/.bashrc,也不自动 cd 到你的项目目录。结果就是:require 'vendor/autoload.php' 找不到,file_put_contents('log.txt', ...) 写到根目录甚至权限拒绝。
实操建议:
- 在脚本第一行写 #!/bin/bash
- 紧接着用 cd /www/wwwroot/example.com 切到项目根目录
- 如果脚本依赖环境变量(如数据库密码),在 cd 后加 source .env 或显式 export DB_HOST=xxx
- 权限检查:确保 www 用户对项目目录有读写权,chown -R www:www /www/wwwroot/example.com
避免重复执行和端口冲突的关键判断逻辑
定时任务设成“每分钟”,但 Swoole 或长时任务不能反复启动,否则报 Address already in use 或进程堆积。
不要靠“禁止重复执行”勾选项来保命——它只防同一时刻并发,不防进程已存在却还硬启。
必须自己加判断:
- 检查端口:用 lsof -i :9501 | grep LISTEN(替换为你监听的端口)
- 或检查进程:用 pgrep -f "start.php start"(替换为你的启动命令关键词)
- 只有没命中才执行启动命令,否则跳过
示例片段:if ! lsof -i :9501 | grep LISTEN > /dev/null; then /www/server/php/82/bin/php /www/wwwroot/app/start.php start -d; fi
立即学习“PHP免费学习笔记(深入)”;
真正麻烦的不是写命令,而是每次换 PHP 版本、换项目路径、换端口时,这些路径和判断条件全得手动同步——漏改一处, cron 就静默失效。日志里看不到报错,进程列表里也找不到痕迹,只能挨个验证路径、权限、端口、用户上下文。



















