ITFlow 26.10 常用 CLI 命令与工具详解
ITFlow 26.10 命令行工具实测:cron.php 调度器与 9 个任务脚本逐个回显、setup_cli/update_cli/restore_cli 运维三件套用法、锁文件机制与排障实录。
ITFlow 26.10 常用 CLI 命令与工具详解
目标:盘点 ITFlow 26.10 服务器侧的命令行工具——每分钟被 cron 拉起的任务调度器
cron/cron.php及其 9 个注册任务脚本、scripts/下的三个官方运维脚本(安装/更新/恢复),给出逐个的直跑实测回显、运行身份纪律与故障实录。本文所有命令与回显均在 Ubuntu 22.04.5 LTS 实机实例上实测采集(ITFlow v26.10,git 标签)。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS |
| ITFlow | v26.10(APP_VERSION = "26.10",数据库版本 2.7.9) |
| PHP CLI | 8.3.36 |
| 站点目录 | /var/www/html(属主 www-data:www-data) |
| 数据库 | itflow(MariaDB 10.6.23,业务库前缀无、表 141 张) |
| cron 形态 | /etc/cron.d/itflow 每分钟拉起 cron/cron.php |
安装部署过程(含 Web 向导与 setup_cli 静默安装两条路线)见 《Ubuntu 22.04 安装 ITFlow 26.10 指南》;文中涉及的 config.php 参数与 settings 表字段见 《ITFlow 26.10 配置参数详解》。
二、CLI 全景总览
ITFlow 是纯 PHP 应用,没有自研的 shell 二进制,其「CLI 形态」由两组 PHP 脚本构成(均为仓库自带,v26.10 实查):
| 组 | 位置 | 成员 | 调用方式 |
|---|---|---|---|
| 后台任务族 | /var/www/html/cron/ | cron.php(调度器)+ nightly_tasks.php、mail_queue.php、ticket_email_parser.php、domain_refresher.php、certificate_refresher.php、backup.php、app_update.php、update_check.php、ticket_sla.php | 系统 cron 每分钟拉起 cron.php 统一派发;也可对单个脚本直跑排障 |
| 运维脚本族 | /var/www/html/scripts/ | setup_cli.php(静默安装)、update_cli.php(代码+数据库更新)、restore_cli.php(备份恢复) | 手工按需执行 |
💡 技术拓展:这类 PHP 应用的后台任务常见三种门派——应用内嵌触发(用户访问时顺带跑)、常驻队列进程(额外守护进程)、系统 cron 拉起脚本。ITFlow 选第三种:只要一条
* * * * *crontab,无新增常驻进程;代价是任务粒度的调度与状态要自己管——它把这些放在数据库cron_jobs表(见第四节),形成「系统 cron 管节奏、应用管语义」的双层结构。
统一纪律(实测教训沉淀,反复触发):
- 运行身份 = 站点文件属主 www-data。cron.php 及全部子脚本在 /tmp 建锁文件(命名
itflow_cron_<md5(脚本绝对路径)>.lock),并以 git 仓库形态自更新——root 手动直跑会留下 root 属主的锁文件与 .git 文件,随后 www-data 的系统调度立即被拒(实录见第七节 FAQ Q1/Q2); - 手动排障用
sudo -u www-data php ...或su -s /bin/bash www-data -c 'php ...'; - 脚本直跑的工作目录不影响执行(脚本内部已处理路径),但保持
cd /var/www/html再跑的习惯更稳。
三、调度器 cron.php 与任务注册表
3.1 调度器本体
cron/cron.php 是唯一需要 crontab 的入口,每分钟做一次「读注册表 → 判断哪些任务到期 → 逐个执行并记录」:
sudo -u www-data php /var/www/html/cron/cron.php
实测回显:无任何输出,退出码 0(正常时静默是设计行为——所有进度与状态都写进 cron_jobs 表而非 stdout)。
系统侧配合(/etc/cron.d/itflow,实测文件内容):
* * * * * www-data php /var/www/html/cron/cron.php >/dev/null
调度是否真的被拉起过,用两个证据核验(实测):
sudo mariadb -u root itflow -e "SELECT config_cron_last_dispatch_at FROM settings;"
实测回显:
config_cron_last_dispatch_at
2026-10-23 23:37:01
journalctl -u cron --no-pager | grep CMD | tail -2
实测回显(节选):
Oct 23 15:37:01 itflow-server CRON[27105]: (www-data) CMD (php /var/www/html/cron/cron.php >/dev/null)
3.2 任务注册表(cron_jobs 表,9 个任务实测全量)
sudo mariadb -u root itflow -e "SELECT cron_job_name, cron_job_schedule, cron_job_interval_minutes, cron_job_daily_at, cron_job_enabled, cron_job_last_status FROM cron_jobs ORDER BY cron_job_id;"
实测回显:
cron_job_name cron_job_schedule cron_job_interval_minutes cron_job_daily_at cron_job_enabled cron_job_last_status
mail_queue Interval 1 NULL 1 Stopped
ticket_email_parser Interval 1 NULL 1 Stopped: Email Parser: Feature is not enabled - check Settings > Ticketing > Email-to-ticket parsing. See https://docs.itflow.org/ticket_email_parse -- Quitting..
ticket_sla Interval 1 NULL 1 Completed
domain_refresher Daily 1 04:00:00 1 Stopped: Cron: is not enabled -- Quitting..
nightly_tasks Daily 1 03:00:00 1 Stopped: Cron: is not enabled -- Quitting..
backup Daily 1 02:00:00 1 Completed
certificate_refresher Daily 1 03:30:00 1 Stopped: Cron: is not enabled -- Quitting..
update_check Daily 1 02:30:00 1 Stopped: Cron: is not enabled
app_update Daily 1 05:00:00 0 NULL
要点解读(实测观察):
cron_job_schedule两种取值:Interval(按cron_job_interval_minutes周期跑)与 Daily(按cron_job_daily_at时刻跑);app_update出厂即enabled=0——只有当你在 Maintenance > Update 页点了 Queue Update 它才会被拉起干活;cron_job_last_status是排障第一入口:Completed 正常;Stopped: … 带原因(本实例的 mail_queue=Stopped 表示队列为空、ticket_email_parser=Stopped 是因为邮件转工单未启用,都是预期行为而非故障);- 表内还有
cron_job_last_run_at、cron_job_last_finish_at、cron_job_last_duration、cron_job_last_error字段(实测 SHOW COLUMNS 可见),分别记录最近运行时刻、结束时刻、耗时与错误原文; - 总开关在
settings.config_enable_cron(实测出厂 0,Maintenance > Cron 页打开后为 1)——关闭时 Daily 任务的 last_status 会如实记上Stopped: Cron: is not enabled -- Quitting..。
3.3 锁机制(为什么不能多身份混跑)
cron/includes/cron_lock.php(源码注释实读)说明了设计:同一任务不可并发两次(自动扣款、发邮件、建工单重复都是事故),锁文件名取 md5(脚本绝对路径),用 flock 而非「检测文件存在」——flock 由内核在进程退出时释放,被杀的运行不留死锁;锁文件打不开(属主/权限问题)才算真故障,会大声报错。这就解释了 FAQ Q1 的现象:锁文件属主一旦被 root 污染,www-data 的 fopen 直接 Permission denied。
四、cron/ 任务脚本逐个实测
以下回显均为 su -s /bin/bash www-data -c 'php cron/<脚本>.php' 的真实直跑输出。
4.1 mail_queue.php —— 发件队列(每分钟)
职责:把系统积压的出站邮件(工单通知、发票、密码共享等)经 SMTP 发出去。
sudo -u www-data php /var/www/html/cron/mail_queue.php
实测回显:无输出,退出码 0(队列为空时的正常表现)。
4.2 ticket_email_parser.php —— 邮件转工单(每分钟)
职责:从 IMAP 拉取客户来信,按规则建票/回票。
sudo -u www-data php /var/www/html/cron/ticket_email_parser.php
实测回显(全文):
Email Parser: Feature is not enabled - check Settings > Ticketing > Email-to-ticket parsing. See https://docs.itflow.org/ticket_email_parse -- Quitting..
未启用该功能时每次自行跳过,属预期行为;启用入口在后台 Settings 的工单设置。
4.3 ticket_sla.php —— SLA 监控(每分钟)
职责:按 SLA 策略检查临期/超期工单并触发告警。
sudo -u www-data php /var/www/html/cron/ticket_sla.php
实测回显:无输出,退出码 0;cron_jobs 表中该任务 cron_job_last_status = Completed。
4.4 nightly_tasks.php —— 夜间维护(每日 03:00)
职责:夜间大扫除——清理、自动关闭到期工单、各类提醒、循环发票落地等(官方 cron 文档口径 "cleanup, auto-closing resolved tickets, alerts, recurring invoices, etc.")。
sudo -u www-data php /var/www/html/cron/nightly_tasks.php
实测回显:无输出,退出码 0。
4.5 domain_refresher.php —— 域名信息刷新(每日 04:00)
职责:刷新 ITFlow 台账内域名的到期日与解析/whois 信息。依赖系统安装的 whois 客户端(Ubuntu 包名即 whois,见 B 篇 4.1 节安装清单)。
sudo -u www-data php /var/www/html/cron/domain_refresher.php
实测回显:无输出,退出码 0(实例无域名台账时静默)。
4.6 certificate_refresher.php —— 证书信息刷新(每日 03:30)
职责:刷新台账内 TLS 证书的到期日、签发者、密钥位长。
sudo -u www-data php /var/www/html/cron/certificate_refresher.php
实测回显:无输出,退出码 0。
4.7 backup.php —— 计划备份(每日 02:00,出厂关闭)
职责:① 构建计划备份(任务启用时);② 处理 Web 端排队的备份请求。
sudo -u www-data php /var/www/html/cron/backup.php
实测回显:
- 任务未启用时:
Scheduled backups are switched off - built queued work only - 任务启用后(实测已开启):
Scheduled Full Backup complete
备份包落在 uploads/backups/,并登记进 backups 表(实测回显):
backup_file_name backup_size backup_status backup_source
itflow_20261023-233527_full_m-gi5Kk0HsVtFbW7qhioTff0oEhjrpaW.zip 19260 Complete Cron
⚠️ 注意:首次构建备份后 config.php 会追加备份加密密钥(
$config_backup_key),丢失该密钥备份即不可恢复,务必抄录保存(详见 C 篇 3.10 节)。
4.8 app_update.php —— 落地排队更新(每日 05:00,出厂关闭)
职责:执行 Web 界面 Maintenance > Update 排队的更新任务(拉代码 + 应用数据库迁移)。
sudo -u www-data php /var/www/html/cron/app_update.php
实测回显(无排队更新时):
No update queued
4.9 update_check.php —— 更新检查(每日 02:30)
职责:对 git 远端做 fetch,报告落后几个提交。远端可达时的实测回显:
0 commit(s) behind the remote
远端不可达时的实测报错(退出码 255):
PHP Fatal error: Uncaught Exception: git fetch failed: fatal: unable to access 'https://github.com/itflow-org/itflow.git/': GnuTLS recv error (-54): Error in the pull function. in /var/www/html/cron/update_check.php:69
该任务依赖 git 出网;网络受限服务器需为 www-data 的 git 配置代理(sudo -u www-data git config --global http.proxy http://代理地址:端口)或接受每日检查失败——失败仅影响「落后提醒」,不影响业务。
五、scripts/ 运维脚本实测
5.1 setup_cli.php —— 静默安装
全新实例的无人值守安装器(与 Web 向导等价:写 config.php、导入 141 张表、建首个管理员)。完整参数与实测安装流程见 《Ubuntu 22.04 安装 ITFlow 26.10 指南》 方案 B,要点速记:
php /var/www/html/scripts/setup_cli.php --help # 查看全部参数
php /var/www/html/scripts/setup_cli.php --host=... --username=... \
--password=... --database=... --base-url=... --locale=en_US \
--timezone=Asia/Shanghai --currency=USD --company-name="..." \
--country=China --user-name=... --user-email=... --user-password=... \
--non-interactive
--help 实测回显确认的必选参数 13 个(host/username/password/database/base-url/locale/timezone/currency/company-name/country/user-name/user-email/user-password),可选参数含 --address/--city/--state/--zip/--phone/--company-email/--website/--repo-branch,另有 --non-interactive(缺参即失败)。
5.2 update_cli.php —— 代码与数据库更新
sudo -u www-data php /var/www/html/scripts/update_cli.php --help
实测回显(全文):
Usage: php update_cli.php [--update_db]
With no options, updates the application to the latest code on the branch this
install tracks, discarding local changes to tracked files, and then applies any
outstanding database updates.
--update_db Apply outstanding database updates only. The application files
are left exactly as they are - git is not run at all.
用法解读:
- 无参数 = 完整升级:代码硬重置到 $repo_branch 最新 + 应用未落地的数据库迁移(26.10 升级说明同口径);
--update_db= 只补数据库迁移、完全不碰 git(适合代码已手动到位、只差 schema 的场景);- 属主校验是硬门槛:root 直跑实测被拒(退出码 1):
Error: This script must be run by the file owner (www-data) to proceed.
You could try sudo -u www-data php update_cli.php
5.3 restore_cli.php —— 备份恢复
php /var/www/html/scripts/restore_cli.php --help
实测回显(全文):
Usage: php scripts/restore_cli.php --file=/path/to/backup.zip [--key=KEY] [--inspect] [--yes]
--file=PATH The backup archive to restore. Required.
--key=KEY Encryption key. Defaults to $config_backup_key from config.php.
--inspect Show what is in the archive and exit without changing anything.
--yes Skip the confirmation prompt.
恢复演练第一步永远是检视(对实测生成的备份包执行 --inspect 的真实回显):
Backup archive: itflow_20261023-233527_full_m-gi5Kk0HsVtFbW7qhioTff0oEhjrpaW.zip
Size: 18.8 KB
Type: Full Backup
Taken: 2026-10-23 23:35:27
ITFlow version: Unknown
Database version: 2.7.9
Contains: db.sql, uploads.zip, version.txt
This install is at database version 2.7.9.
--inspect given, nothing was changed.
包内容 = db.sql(全库转储)+ uploads.zip(上传文件)+ version.txt(版本标记);密钥默认取 config.php 的 $config_backup_key,也可用 --key 显式给。确认无误后加 --yes 才会真正写库。
六、典型运维场景串联
把上文命令按场景串起来(全部命令在本实例实测可跑通):
- 晨检三连:
SELECT cron_job_name, cron_job_last_status FROM cron_jobs(有无非预期 Stopped)→SELECT config_cron_last_dispatch_at FROM settings(调度是否活着)→sudo -u www-data php /var/www/html/cron/mail_queue.php(手动补一发邮件队列); - 手动触发一次全量备份:
sudo -u www-data php /var/www/html/cron/backup.php→ 确认Scheduled Full Backup complete→--inspect检视新包 → 抄录/核对 $config_backup_key; - 月度升级:先
sudo -u www-data php /var/www/html/cron/update_check.php(或 Web 端 Maintenance > Update)确认落后提交 → 备份(上一条)→sudo -u www-data php /var/www/html/scripts/update_cli.php(代码+库一次到位)→ 再跑一次 update_check 归零、巡检 cron_jobs; - 恢复演练(换环境验证备份可用):准备等版本空实例 →
restore_cli.php --file=... --inspect检视 →--yes恢复 → 登录核验。
七、常见问题(FAQ)
Q1:手动跑过一次脚本后,系统 cron 的该任务开始报锁文件权限错误?
实录(www-data 执行时的真实报错):
PHP Warning: fopen(/tmp/itflow_cron_696309544e04e1eb7f6819c8a312c17f.lock): Failed to open stream: Permission denied in /var/www/html/cron/includes/cron_lock.php on line 80
Cannot open the cron lock file at /tmp/itflow_cron_696309544e04e1eb7f6819c8a312c17f.lock - check permissions and open_basedir.
原因:曾以 root 直跑,锁文件(命名 = md5(脚本绝对路径),每脚本一把)属主变成 root。修复:sudo rm -f /tmp/itflow_cron_*.lock,之后只以 www-data 运行。锁文件随时可删——flock 语义下删除后下一次运行会重建。
Q2:update_check 报 git fetch failed(Permission denied: .git/FETCH_HEAD)?
实录:
PHP Fatal error: Uncaught Exception: git fetch failed: error: cannot open .git/FETCH_HEAD: Permission denied in /var/www/html/cron/update_check.php:69
原因:root 直跑过 git 类任务,.git 内出现 root 属主文件。修复:sudo chown -R www-data:www-data /var/www/html,实测修复后恢复。治本同 Q1——统一 www-data 身份。
Q3:update_check 报 GnuTLS recv error?
实录见 4.9 节。是出网到 GitHub 的 TLS 握手故障(网络/代理问题),不是应用故障:为 www-data 的 git 配代理或放宽检查频率;该任务失败不影响其他任务(调度器逐任务隔离)。
Q4:为什么有的任务 last_status 是 Stopped 却说不是故障?
cron_jobs 的 Stopped 只表示「本次没有做事」,后缀是原因。实测样例:mail_queue 空队列 → Stopped;ticket_email_parser 未启用 → Stopped: Email Parser: Feature is not enabled...;总开关没开 → Stopped: Cron: is not enabled -- Quitting..。看后缀定性,Completed 与带预期原因的 Stopped 都属正常。
Q5:能把任务从 cron 挪到别的调度器(systemd timer)吗?
可以但没必要。cron.php 自带应用层的幂等与锁(flock + cron_jobs 记账),systemd timer 只需同样以 www-data 身份每分钟拉起 php /var/www/html/cron/cron.php 即可等价替代 /etc/cron.d 条目;任务语义仍由 Maintenance > Cron 页管理。
八、参考链接
- 官方 cron 文档(脚本职责表):https://docs.itflow.org/cron (查询日期 2026-10-23)
- 官方邮件转工单文档:https://docs.itflow.org/ticket_email_parse (查询日期 2026-10-23)
- 官方备份文档:https://docs.itflow.org/backups (查询日期 2026-10-23)
- 源码仓库(scripts/ 与 cron/ 全部脚本):https://github.com/itflow-org/itflow (v26.10 标签,查询日期 2026-10-23)
- 同专栏 《ITFlow 26.10 介绍与选型指南》、《Ubuntu 22.04 安装 ITFlow 26.10 指南》、《ITFlow 26.10 配置参数详解》