适用版本 v1.3.5 | 主控端—被控端架构

被控端(仓库管理系统)开发文档

面向二次开发 / 运维 / 发布人员:架构、目录、配置约定、在线逐级更新机制、补丁发布流程与部署方式。

1. 架构总览

┌─────────────┐        授权 / 公告 / 版本更新        ┌──────────────────┐
│  主控端       │  ───────────────────────────────▶  │  被控端(仓库)    │
│ (平台 / 管控)│  ◀───────────────────────────────  │  (业务 / 仓储)   │
└─────────────┘   版本上报 / 反馈上报 / 升级日志       └──────────────────┘
  • 主控端:负责“管控面”——授权签发、版本发布与逐级下发、公告多系统下发、意见反馈归集。对外提供标准 HTTP 接口(如 api/version.php)。
  • 被控端:负责“业务面”——物料、库存、盘点、统计大屏等仓储作业,以及本地业务数据。通过接口与主控协同,支持在线逐级更新。

关键契约

  • 被控端 api/check_update.php 上报 from=当前版本,主控仅返回“下一级”版本。
  • 被控端 api/do_update.php 下载、校验、复制补丁并写入新版本号,可一次请求内逐级循环到最新。
  • 补丁包内含 manifest.json,其 from_version 做跳版本硬校验(不允许跨版本直更)。

2. 技术栈与运行环境

项要求
语言PHP 7.4 或 8.x(已验证 7.4.33 / 8.5.8)
数据库MySQL 5.7+(已验证 5.7.44)
扩展mysqli / curl / mbstring / zip / openssl(GD 视功能可选)
运行方式任意 Web 服务器(Nginx/Apache)或 php -S 内置服务器
依赖vendor/(PhpSpreadsheet 等,仓库导入导出使用;通过 vendor/autoload.php 引入)
Windows 本地部署提示:若页面访问缓慢,优先检查 config.php 的 DB_HOST 是否为 localhost——Windows 下 PHP 会优先解析 IPv6 ::1 而 MySQL 通常只听 IPv4,导致连接重试变慢,改为 127.0.0.1 即可。

3. 目录结构

被控端/
├─ index.php              入口(前端页面路由)
├─ login.php / logout.php 登录登出
├─ dashboard.php          首页仪表盘(含「物料 0 库存」KPI)
├─ statistics.php         统计大屏 / 概览
├─ settings.php           系统设置(主控接入、开发者模式)
├─ feedback.php           意见反馈
├─ install.php / install.sql   安装向导与建表脚本
├─ _router.php            php -S 开发路由(仅开发用)
├─ api/
│  ├─ check_update.php    检查更新(上报 from=当前版本)
│  ├─ do_update.php       在线更新(逐级循环升级引擎)
│  ├─ feedback_*.php      反馈提交/回复/删除/同步
│  └─ master_guard.php    主控接入守卫
├─ includes/
│  ├─ config.php          ⚠️ 数据库凭据与环境配置(受保护,更新不下发)
│  ├─ defs.php            ✅ 应用级常量/函数(可随更新下发)
│  └─ ...
├─ warehouse/             仓储业务(导入导出依赖 vendor/autoload.php)
├─ users/                 用户/员工
├─ storage/               运行时:上传、日志、更新备份(不上发、不发布)
├─ uploads/               运行时上传目录
├─ vendor/                第三方依赖(必须保留)
└─ manifest.json         当前版本清单(由发布脚本生成)

两个配置文件的分工(非常重要)

文件内容是否随在线更新下发说明
includes/config.php DB 账号密码、站点名、SITE_VERSION、存储驱动、Session 配置 否(受 $block 保护) 含敏感凭据,更新时绝不覆盖,避免冲掉用户的环境配置
includes/defs.php DEFAULT_MASTER_URL、effective_master_url()、UPDATE_CHAIN、update_chain_next() 等应用级定义 是 多处代码依赖,抽到本文件可被正常下发
⚠️ 铁律:新增的「应用级常量 / 函数 / 类」一律放 includes/defs.php(或新的独立可下发文件),严禁写进 includes/config.php。因为 config.php 受保护不下发,若把新常量写在那,线上旧 config.php 缺这些符号 → 页面报“未定义”、内联 JS 被破坏、功能点不动。历史上 1.3.3→1.3.4 的“系统设置无法点击”正是此坑。

4. 配置系统

includes/config.php 关键常量:

define('DB_HOST', '127.0.0.1');
define('DB_USER', 'wg_app1');
define('DB_PASS', 'App1#2026');
define('DB_NAME', 'wg_app1');
define('DB_PORT', 3306);

define('SITE_NAME',     '出入库管理系统');
define('SITE_VERSION', '1.3.5');

define('STORAGE_DRIVER',   'local');   // local | cos
define('LOCAL_UPLOAD_DIR', __DIR__ . '/../uploads');
define('LOCAL_UPLOAD_URL', '/uploads');
  • 支持 config_override.php(若存在则被 require_once,用于环境差异覆盖)。
  • 文件末尾 require_once __DIR__ . '/defs.php'; 引入应用级定义。
  • 版本号有两个来源:SITE_VERSION 常量(代码内置)与 app_version() 设置项(数据库,更新成功后由 save_setting('app_version', …) 写入)。显示/更新判断以设置项为准;若设置项缺失则回退常量。

5. 在线更新机制(核心)

5.1 角色

组件位置职责
check_update.php被控端 api/带 from=当前版本 请求主控,返回“下一级”版本与下载地址(仅用于展示)
do_update.php被控端 api/逐级循环升级引擎(实际执行更新)
version.php主控 api/按升级链返回“大于 from 的最小已发布版本”;无 from 时返回最低已发布版本(用于旧客户端自举)
manifest.json每个补丁包内声明 version 与 from_version,供跳版本硬校验

5.2 被控端 do_update.php 主流程(逐级循环)

POST api/do_update.php(仅超级管理员)
  └─ while 未到最新 且 步数 < 上限:
       1. 拼装更新源地址(与 check_update 一致),追加 from=当前版本
       2. fetch version.php → 得到下一级 {version, download_url, from_version}
       3. 下载 zip → 解压到临时目录
       4. 读取 manifest.json,硬校验 manifest.from_version === 当前版本
          (不等 → 拒绝“跳版本”,返回友好提示)
       5. 遍历文件复制(带备份),跳过 $block 受保护文件
       6. save_setting('app_version', 下一级版本) → 写日志 → 上报主控升级日志
       7. 当前版本 = 下一级,进入下一轮循环
  └─ 返回:{ok:true, steps, path:[...], version:最新}
旧版被控端(如 1.3.0)的 do_update.php 不带 from,会直接拉到最新版被 from_version 硬拒而无法自举。主控 version.php 的无 from 兜底改为“返回最低已发布版本(桥接包)”,旧客户端先装上新的 do_update.php 引擎,下一次更新即可自动逐级走到最新。因此旧客户端需点两次更新:第一次激活引擎,第二次一步到底。

5.3 受保护文件($block)

更新复制阶段不会覆盖以下文件(避免冲掉环境与凭据):

$block = [
  'includes/config.php',
  'includes/config_override.php',
  'install.lock',
  '.env',
  'composer.lock',
];

5.4 补丁包 manifest.json 示例

{
  "version": "1.3.5",
  "from_version": "1.3.4",
  "changelog": "新增物料 0 库存统计(首页/统计大屏/概览)。",
  "generated_at": "2026-07-30"
}

6. 发布补丁流程

补丁构建脚本:发布包/build_chain.php,产出 发布包/chain_x.x.x_to_y.y.y/。

6.1 两种补丁类型

  • 桥接补丁(如 1.3.0→1.3.1):仅含“链式三件套” includes/defs.php + api/do_update.php + api/check_update.php + manifest.json。用于让旧版本获得逐级升级能力并推进版本号。
  • 完整树补丁(如 1.3.3→1.3.4、1.3.4→1.3.5):完整程序树(排除 storage/vendor 运行缓存等)+ 叠加三件套。保证到达该版本时为完整且正确的程序状态。
经验:完整树基线一律使用干净源码(如 被控端1),不要用混淆/历史产物当基线——混淆构建可能把函数调用当参数默认值导致致命解析错误。

6.2 文件命名

补丁 zip 使用 ASCII 文件名(如 slave_1.3.0_to_1.3.1.zip)。部分服务器对中文名 zip 下载会返回 0 字节 / 404,务必避免中文名。

6.3 校验

  • 发布包/lint_chain.php:自包含 PHP(ZipArchive 解压 + php -l)对全部补丁内 php 文件做语法检查。
  • 发布包/verify_chain.php:校验各 manifest 与文件名一致、链式引擎存在、模拟 version.php 链无跳版、关键特性(如 0 库存 KPI)就位、无混淆残留。

6.4 发布到主控

  1. 将 5 个补丁 zip 上传到主控 uploads/。
  2. 后台「产品更新 / 版本」依次新建已发布记录:版本号 name 与下载文件 file(指向 uploads/slave_*_to_*.zip)。
  3. 修复版 api/version.php 已使无 from 兜底返回最低已发布版本(旧客户端自举必需)。

7. 接口契约(摘要)

接口方法关键参数返回要点
主控 api/version.phpGETfrom(当前版本)、auth_codeversion/download_url/from_version/step/has_update/authorized;无 from 返回最低已发布版本
被控 api/check_update.phpGETfrom、auth_codelatest/changelog/has_update
被控 api/do_update.phpPOST仅超级管理员ok/version/steps/path;逐级循环结果
被控 api/feedback_*.phpPOST/GET授权相关反馈提交/回复/列表(支持分页)
被控 api/master_guard.php——主控接入守卫
授权:被控端需在「系统设置」绑定主控授权码(license_key)。未授权/过期时主控 version.php 返回 authorized:false,不下发下载地址。

8. 部署

8.1 全新安装

  1. 将完整安装包解压到 Web 根(保留 vendor/)。
  2. 确保 storage/、uploads/ 可写。
  3. 浏览器访问 install.php → 按向导填写数据库信息(建库后用 install.sql 建表;导入前 SET FOREIGN_KEY_CHECKS=0 避免外键顺序报错)。
  4. 安装完成生成 install.lock。

8.2 多实例(同机多仓库)

每个被控端实例使用独立端口 / 独立库 / 独立用户 / 独立 Session 目录,避免串号:

php -S 127.0.0.1:8083 -d session.save_path=/tmp/sess_wg_app1 _router.php
php -S 127.0.0.1:8084 -d session.save_path=/tmp/sess_wg_app2 _router.php
# 各自 includes/config.php 指向独立库 wg_app1 / wg_app2 ...

8.3 在线更新(用户侧)

后台「系统设置 → 检查更新」→ 显示可升到的下一级 → 「立即更新」。新引擎下一次请求内自动逐级走到最新。

9. 二次开发指南

9.1 新增一个业务页面

  1. 在根目录或业务目录新建 xxx.php,顶部 require_once 公共头(含 config.php/defs.php 与登录校验)。
  2. 复用现有 requireLogin() / requirePermission() 做权限控制(定义在 includes/config.php)。
  3. 模板风格参考 dashboard.php / statistics.php。

9.2 新增一个 API

  1. 在 api/ 下新建 api/xxx.php,开头 requireLogin() + 角色校验。
  2. 返回 JSON 时统一 header('Content-Type: application/json; charset=utf-8'); echo json_encode(..., JSON_UNESCAPED_UNICODE);。

9.3 新增应用级常量 / 函数

  • 必须放入 includes/defs.php(或新建独立可下发文件并在各处 require_once),切勿写入 config.php。
  • defs.php 顶部有 if (defined('DEFAULT_MASTER_URL')) return; 防御重复加载,新增定义无需重复该守卫。

9.4 资源与静态文件

  • 上传文件走 LOCAL_UPLOAD_DIR(本地)或 COS(配置 STORAGE_DRIVER='cos')。
  • 不要在被下发文件中引用会被 $block 排除的路径(config.php 等)。

10. 常见问题

现象可能原因处理
检测不到主控版本check_update.php 源取错 / 主控未发布对应版本确认默认模式使用 effective_master_url();主控需发布该版本的“下一级”记录
跨版本更新被拒补丁 from_version 与当前版本不符逐级更新,不可跳版;旧客户端先升到 1.3.1 激活引擎
系统设置点不开旧 config.php 缺新常量(部署断裂)应用含 defs.php 的热修补丁;新常量一律放 defs.php
页面访问慢DB_HOST=localhost 在 Windows 解析 IPv6 慢改为 127.0.0.1
下载补丁 0 字节 / 404补丁 zip 用了中文名改用 ASCII 文件名(slave_*_to_*.zip)
更新后功能异常config.php 被误覆盖确认 $block 含 includes/config.php;不要整体覆盖完整包冲掉配置
文档随版本迭代维护;如与代码不符,以代码与 includes/defs.php 注释为准。