断网时 composer install 拒绝重写 composer.lock 的唯一可靠方式是使用 --locked 参数,它严格校验 lock 文件存在性、合法性及版本兼容性,不接受 --with 或 --ignore-platform-reqs 等覆盖参数。

断网时 composer install 拒绝重写 composer.lock 的唯一可靠方式
必须用 --locked 参数,否则 Composer 在检测到 lock 文件缺失、损坏或与 composer.json 不兼容时,会静默重建它——哪怕你只是想“装一遍”,也等于偷偷改了依赖快照。
-
composer install --locked会严格校验:composer.lock必须存在、JSON 合法、含packages字段,且所有包版本不违反composer.json中的约束(例如 lock 记的是"monolog/monolog": "3.0.0",但 json 写的是"^2.0",就会报错退出) - 它不接受任何覆盖参数,如
--with或--ignore-platform-reqs;也不兼容--dry-run - CI/CD 部署脚本里,
composer install --locked --no-dev --no-interaction应是标配,不是可选项
为什么只复制 vendor/ 和 composer.lock 还可能触发网络请求?
因为 composer install 默认会尝试执行 autoload 生成、插件钩子(如 post-install-cmd)、平台扩展检测等操作——这些环节一旦失败(比如缺 ext-zip),Composer 可能 fallback 到重新解析依赖,进而连 Packagist。
- 加
--no-scripts --no-plugins能跳过绝大多数非必要动作,让安装真正变成“解压+写文件” - 若项目依赖某些必须运行的插件(如
ocramius/package-versions),则不能关插件,此时必须确保离线机 PHP 环境(含扩展、版本)与构建机完全一致 -
--ignore-platform-reqs是危险开关:它绕过扩展/PHP 版本检查,可能导致运行时报错,仅限临时调试,不可用于生产
缓存路径没对上,composer.lock 就是废的
Composer 不是从 vendor/ 读包,而是从全局缓存(~/.composer/cache/files/)按 dist.shasum 找 ZIP 文件。如果离线机缓存路径不同、或缓存被清空,它仍会报“package not found”,哪怕 vendor/ 里代码全在。
- 联网机打包前,先执行:
composer config --global cache-files-dir /path/to/shared/cache,再跑composer install --prefer-dist,确保所有 ZIP 下载到指定位置 - 离线机上运行:
composer config --global cache-files-dir /path/to/shared/cache,路径必须一字不差 - 验证缓存是否完整:进
/path/to/shared/cache/files/,看每个包目录下是否有对应version-hash.zip(如monolog/monolog/7f10e4d9a18b95c6b1202f67597c5f6e.zip),文件名要和composer.lock里dist.shasum完全一致
用 artifact 仓库替代全局缓存更可控
当无法统一缓存路径(比如多用户、权限受限环境),直接把 ZIP 包扔进项目本地目录,再用 artifact 类型仓库声明,比依赖全局配置更鲁棒。
- 把联网机
~/.composer/cache/files/下所有 ZIP 拷进离线项目根目录的artifacts/子目录 - 在
composer.json里加:{"repositories": [{"type": "artifact", "url": "./artifacts/"}]} - 运行:
composer install --prefer-dist --no-scripts --no-plugins—— 此时 Composer 只查./artifacts/,彻底绕开全局缓存和网络
content-hash 的计算可能有微小差异,导致 --locked 直接失败。离线部署前,务必确认 php -v 和 composer --version 与构建环境完全相同。










