composer install 必须有 composer.lock 才能离线成功,因其唯一固化了各包的确切版本、dist url 和 shasum 校验值;无 lock 时会退化为需联网的 update 行为。

composer install 为什么必须有 composer.lock 才能离线成功?
因为 composer.lock 是唯一记录「每个包确切版本、dist URL、shasum 校验值」的文件。没有它,composer install 就会退化成 composer update,强行联网解析依赖——哪怕你本地缓存全都有,也会报 Could not fetch https://repo.packagist.org/packages.json。
-
composer.json只写约束(如"monolog/monolog": "^2.0"),运行时要查远程元数据才能确定装哪个具体版本 -
composer.lock把所有决策结果固化下来:比如"version": "2.10.0"、"dist": {"shasum": "7f10e4d9a18b..."},Composer 看到这个就跳过联网,直接去缓存或 vendor 里找对应 zip - 删了 lock 文件又想离线装?不可能。必须回联网环境重新
composer update或composer install生成一份新的
怎么确保 composer.lock 能在离线机上真正起作用?
光拷贝文件不够,它得和本地资源严格对齐。常见失败不是 lock 缺失,而是内容“不匹配”——比如 PHP 版本变了、缓存路径不对、或者 ZIP 文件被删了一两个。
- 检查
composer.lock里的content-hash字段:它由composer.json+ 当前平台信息(PHP 版本、扩展列表)共同生成;离线机 PHP 版本不同,composer install会直接拒绝执行 - 确认所有
dist.shasum对应的 ZIP 文件真实存在:进~/.composer/cache/files/,按vendor/name/sha256hash.zip路径搜索,缺一个就会卡在Package not found - 别用
--ignore-platform-reqs图省事:它绕过 PHP 版本/扩展检查,但可能导致composer.lock中的platform段失效,后续 autoload 或插件行为异常
离线机上运行 composer install 的最小安全命令是什么?
不是加一堆 flag 就安全,而是用最少参数、最明确意图来堵死网络出口。重点是让 Composer 相信“所有东西我都准备好了,别连网”。
- 必须带
--no-network:这是硬开关,强制禁用所有 HTTP 请求,不加它,哪怕缓存全在,也大概率因 metadata 检查失败而中断 - 推荐加
--no-scripts --no-plugins:很多 post-install-cmd 会尝试调用外部命令或加载远程配置,这些环节容易触发隐式联网 - 不要加
--prefer-dist:它只影响下载策略,离线时没意义;反而可能因找不到 dist 而 fallback 到 source,引发 git 克隆失败 - 正确命令示例:
composer install --no-network --no-scripts --no-plugins
为什么直接复制 vendor/ 目录有时仍会触发网络请求?
因为 vendor/ 不是“最终态”,它只是中间产物。Composer 在 install 过程中会做几件事:校验 autoload、执行插件、重建 installed.json——这些步骤如果配置或环境不一致,就可能悄悄发起网络调用。
- 比如某包含
composer-plugin-api插件,它的activate()方法里写了file_get_contents('https://...'),composer install会照常加载并执行 - 再比如
vendor/autoload.php被删了,Composer 会自动重建,但如果 autoloader 配置里引用了未声明的命名空间,它可能试图从 packagist 查包信息 - 更隐蔽的是
composer.lock里某个包的type是package而非library,且定义了dist.url为远程地址——即使你本地有 vendor,Composer 仍会尝试校验那个 URL
所以最稳的离线方案,永远是“lock 文件 + 完整缓存 + –no-network”,而不是赌 vendor 目录能扛住所有边界情况。