﻿QBCMS 低版本升级补丁 v1.4.2 · 安装说明
======================================================================

【适用站点】
  1) 当前程序版本为 V1.2.0、V1.2.1 …… V1.3.0 的 QBCMS 站点：本补丁为其补齐
     1.2.0 → 1.3.0 增量并替换升级器，之后可一次升到 v1.4.2。
  2) 已升到 V1.3.0 / V1.4.0 / V1.4.1 / V1.4.2，但前台无法访问（报错，或停留在
     「系统更新 / 当前版本 v」这类空白页）的站点：本补丁的「根目录入口文件修复」
     可把被回滚误写覆盖的根目录入口文件恢复为官方内容。
  版本低于 V1.2.0 的站点请先升级到 V1.2.0 再使用本补丁。

【为什么需要它】
  后台「系统更新 → 检测更新」能探测到 v1.4.2，点「升级」却提示
  「该路径受保护，不允许在更新包中修改：static/member/contribution/create.html」
  并在回滚后中止。原因有三个：

  1) 旧版升级器把 static/ 整目录列为受保护前缀，v1.4.1 / v1.4.2 升级包中
     有一个受保护前缀下的会员投稿模板，命中即整包中止。官方 v1.4.2 升级器已加入
     static/member/ 例外放行规则，本补丁就是把这一版升级器带给老站点。

  2) 旧版升级器在「升级失败回滚」时存在落盘路径缺陷：回滚时没有带上镜像内的相对
     目录，而是把包内的嵌套文件按文件名（basename）写到了站点根目录。后果之一就是
     站点的根目录入口文件被同名副本覆盖 —— 例如 admin/views/update/index.php 会把
     根目录的 index.php 覆盖成「系统更新」页模板。此时前台直接报 500 或显示
     「系统更新 / 当前版本 v」，而后台仍可登录、升级也会显示成功。
     官方 v1.4.2 升级器已修正落盘路径；但已经被写坏的文件不会自愈：
       · v1.4.2 增量包不含根目录 index.php（该文件自 v1.3.0 起内容未再变动），
         升级不会把它写回来；
       · 本补丁的 1.3.0 增量层只在站点版本低于 1.3.0 时执行，1.3.0 及以上站点
         拿不到这一层。
     这正是「v1.2.0 安装后升级失败 → 用补丁修复 → 升级成功 → 前台正常」与
     「v1.3.0 安装后升级失败 → 用补丁修复 → 后台显示已升到 v1.4.2 → 前台仍然打不开」
     两条路径表现不同的原因。本补丁新增的「根目录入口文件修复」就是补上这一环。

  3) v1.4.2 升级包是相对 v1.3.0 基线打包的。V1.2.0 站点直接升 1.4.2 会缺少
     V1.2.0 → V1.3.0 那一层的 25 个文件、并遗留 7 个待删文件（老客户端又只会
     直连最新版，不会自己补这一层）。本补丁在站点低于 1.3.0 时自动补齐这一层，
     并把程序版本号更新为 1.3.0。
     这一层比官方 QBCMS_upgrade_1.3.0.zip 多覆盖一个根目录 index.php：官方 1.3.0
     升级包漏掉了它，导致 1.2.0 站点升上来后前台模板的 {qbcms:version} 标签不可用
     （该文件自 v1.3.0 起内容未再变过，1.3.0 / 1.4.0 / 1.4.1 / 1.4.2 完全一致）。

  补丁装好之后，老客户端仍然直连 v1.4.2 —— 这一次可以一次升到最新版。

【根目录入口文件修复（本次新增）】
  体检页会逐项检查站点根目录的四个入口文件：index.php、web.config、.htaccess、
  captcha.php，并与随包携带的官方 v1.4.2 基线文件比对：
    · 与官方一致            → 显示「正常」，不改动；
    · 缺失                  → 用官方文件补回；
    · 命中「已知嵌套同名副本指纹」→ 判定为回滚误写覆盖，备份后用官方文件恢复；
    · 内容与官方不一致、又无法判定为误写（可能是站点定制）→ 只告警、默认不改动，
      需要在页面上勾选「同时用官方文件覆盖『内容非官方』的入口文件」才会覆盖。
  该能力不改动 config.php、uploads/、data/、cache/、static/、install/ 等目录，
  只处理上述四个根目录入口文件；每次覆盖前都会备份、失败自动回滚。
  只做入口文件修复时不会写幂等标记、也不改版本号，可随时再跑一次。

【包内文件】
  app/Core/Updater.php      官方 v1.4.2 升级器（已含 static/member/ 例外与回滚落盘路径修正）
  upgrade_patch.php         引导脚本（体检 / 自动补齐增量 / 修复根目录入口文件 / 自动回滚 / 自动清理自身）
  step_1.3.0/manifest.json  V1.2.0 → V1.3.0 增量清单
  step_1.3.0/files/…        上述清单对应的文件（25 个覆盖 + 7 个删除）
  step_root/files/…         官方 v1.4.2 根目录入口文件基线（index.php、web.config、.htaccess、captcha.php）
  安装说明.txt               本文件（安装成功后由脚本自动删除）

【安装步骤】
  第 1 步：覆盖升级器
    把本包**解压后**的全部内容，上传/覆盖到站点根目录（即含 config.php、
    index.php、app/、admin/ 的那一层目录）。
    这一步完成后，app/Core/Updater.php 已被替换为官方 v1.4.2 修补版。

  第 2 步：运行补丁脚本（点击按钮，无需复制地址）
    浏览器访问：https://你的域名/upgrade_patch.php
    页面先做只读体检（站点版本、后台目录、升级器校验、data/ 可写、补丁目录可写、
    四个根目录入口文件的状态等），并列出本次将执行的动作；确认无误后，直接点击页面
    上的【立即执行补丁】按钮（站点已在 1.3.0 及以上、只需修入口文件时按钮显示为
    【立即修复入口文件】），一次点击即完成：
      备份 → 补齐 1.3.0 层（低于 1.3.0 时）→ 修复根目录入口文件（如有）→ 更新版本号
      → 写幂等标记 → 删除补丁文件。
    安装结果（覆盖/删除文件数、入口文件修复明细、备份目录、清理情况）直接显示在
    页面上，请留存备查。

    说明：
      · 补丁已改为「页面按钮」单一执行入口：为防被第三方页面误触发，脚本只接受页面
        提交（须带页面下发的一次性口令，且请求来源站点与本机一致）。直接访问带参数的
        地址只会做体检，不会执行任何改动。
      · 页面底部另有【仅清理补丁文件】按钮，可在不执行安装的情况下清掉补丁文件。
      · 站点已在 1.3.0 及以上、且入口文件正常时，脚本会提示无需执行，可直接收尾。

  第 3 步：后台升级
    登录后台 → 系统更新 → 检测更新 → 升级。
    此时可正常升级到 v1.4.2。建议升级前先备份数据库与站点文件；若升级失败，
    系统会自动回滚，站点不受影响。
    仅做入口文件修复的站点（版本已是 1.4.x）：第 2 步完成后即可直接访问前台确认恢复。

  第 4 步：清理（已自动化）
    安装成功后脚本会自动删除站点根目录下四项补丁内容：
      upgrade_patch.php、step_1.3.0/、step_root/、安装说明.txt
    个别主机因权限受限未能删除时，页面会逐项提示，请按提示手动删除对应项。
    注意：app/Core/Updater.php 是站点程序文件（本补丁的价值所在），不属于清理范围。

【回滚】
  补丁执行前的原始文件全部备份在站点的 data/backup/patch_<时间戳>/files/ 下，
  其中 config.php 的原件为 data/backup/patch_<时间戳>/config.php.bak，
  同目录 patch.log 记录了本次实际执行的动作。
  如需回滚：把 files/ 下的文件按原相对路径覆盖回站点即可。
  脚本自身在任一环节失败时也会自动回滚（会在页面上列出回滚项），并且此时不会清理
  补丁文件，可修复问题后再次点击按钮重试。

【常见问题】
  1) 页面提示「app/Core/Updater.php 不是 v1.4.2 修补版」
     说明第 1 步没做或没覆盖成功，请重新上传本包内容后刷新页面（体检为只读，可放心刷新）。
     站点已在 1.4.x、只需修入口文件时，该项只是告警、不阻塞修复。
  2) 页面提示「无法确定站点后台目录名」
     个别站点把 admin/ 改名过。脚本会从 config.php 的 ADMIN_DIR 读取真实后台目录；
     若 ADMIN_DIR 与实际目录不符，脚本会主动中止（避免把文件写进凭空新建的
     admin/ 目录）。请先修正 config.php 中的 ADMIN_DIR 再执行。
  3) 页面提示「data/ 目录不存在或不可写」
     补丁必须能写入备份，请给站点 data/ 目录写权限（Windows 主机注意 IIS 用户权限）。
  4) 升级到 1.4.2 时仍提示「该路径受保护」
     说明第 1 步的升级器没有生效，请确认 app/Core/Updater.php 已是补丁包内的版本
     （其文件 md5 应为 266b1c60ab4efd1c9d0a60405612601f）。
  5) 前台打不开、或停在「系统更新 / 当前版本 v」空白页，后台却正常
     就是本文「为什么需要它」第 2 条描述的入口文件被覆盖。上传本包 → 访问
     upgrade_patch.php → 点【立即修复入口文件】即可，不需要重跑升级。
  6) 体检页显示某个入口文件「内容非官方（未自动改动）」
     站点对入口文件做过定制（例如自加的 index.php 跳转逻辑）时会出现该提示；脚本不会
     动它。确属回滚误写残留的，可勾选页面上的「同时用官方文件覆盖…」后再执行。
  7) 重复安装补丁
     脚本写入幂等标记后默认拒绝重复执行。确需重跑，请按页面提示点击「强制重跑补丁」
     按钮（同样只通过按钮触发，不再使用地址参数）。仅做入口文件修复时不受该标记限制。
  8) 点按钮提示「页面口令校验失败」或「来源站点不一致」
     说明本次请求不是从本站页面点击的按钮发出的，或点击前站点 config.php 已被改动。
     请重新访问 https://你的域名/upgrade_patch.php，在页面上直接点击按钮。
  9) 只想删掉补丁文件、不执行安装
     在体检页点击【仅清理补丁文件】按钮即可，站点文件与版本号不会有任何改动。

【校验值】
  app/Core/Updater.php   md5 = 266b1c60ab4efd1c9d0a60405612601f
  upgrade_patch.php      md5 = dbc1335f8b901ddc95bb6959bdfb6377
  step_root/files/index.php   md5 = 672199fd7a20c494f406ef55771d91dd
  step_root/files/web.config  md5 = fa7bf3eb9087f7b12fca7dc1b8c232e7
  step_root/files/.htaccess   md5 = 60c1f80047e4c04b57310a9d1fb5b740
  step_root/files/captcha.php md5 = f9825fb337b39034859acb8d137e1bf5
  index.php（1.3.0 层）  md5 = 672199fd7a20c494f406ef55771d91dd
    ↑ 该文件既作为 1.3.0 增量层内容（仅站点版本低于 1.3.0 时写入），
      也作为根目录入口基线（根入口被误写覆盖时恢复）

  注意：本补丁只替换升级器、补齐 1.2.0→1.3.0 增量、修复根目录入口文件，
        不改变任何站点业务数据，不涉及数据库表结构。