vendor存在且lock完整时composer install仍报错,是因为Composer默认联网校验元数据,必须设COMPOSER_DISABLE_NETWORK=1并清除全局repo配置、禁用插件与脚本、确保无source类型依赖及PHP环境一致。

为什么 vendor 存在、lock 文件也完整,composer install 还是报错
错误不是因为文件缺失,而是 Composer 在 install 阶段仍会主动请求远程元数据(比如包是否存在、版本是否合法)。这个行为默认开启,且无法跳过——除非你明确切断所有网络通路并绕过高风险环节。
COMPOSER_DISABLE_NETWORK=1 是硬性前提,不设它,所有 --no-xxx 参数都无效。即使 vendor/ 目录完整,只要 composer.json 里写了 "repositories": [{"type": "packagist", "url": false}],COMPOSER_DISABLE_NETWORK=1 下也会直接退出,不是静默忽略。
如果 composer.lock 中某个包标记为 "source" 类型(如 "dev-master" 或 Git URL),离线时无法校验,install 必然失败。全局配置残留 repo.packagist 会导致 fallback 校验,必须运行 composer config --global repo.packagist false 彻底禁用。
composer install 离线执行的最稳命令组合
这组参数不是“可选优化”,而是防止意外联网的强制防护。前提是:vendor/ 已存在、composer.lock 未改动、PHP 版本和必需扩展(mbstring、openssl、zlib)完全一致。
-
--no-plugins:跳过插件初始化,避免phpstan/extension-installer等隐式联网 -
--no-scripts:屏蔽post-install-cmd,防止脚本调用外部 API 或生成配置 -
--no-autoloader:绕过 autoload 重建,某些自定义实现会触发远程类查找
执行完必须立刻补一记:composer dump-autoload -o,否则运行时大概率报 Class not found。
直接复制 vendor 目录行不行
可以,但有硬性前提:
-
vendor/必须和目标机的 PHP 版本完全一致(如 8.2.12 vs 8.2.13 可能因内部 API 微变导致Class not found) - 所有扩展必须已启用:目标机需提前装好
mbstring、openssl、curl等,否则autoload.php加载失败 -
composer.lock必须一并拷贝,且不能被修改;否则composer install会尝试重算依赖 - 含
bin/脚本的包(如phpunit)要求目标机php在$PATH中,且路径与源环境一致
预下载依赖包并打包成离线 tarball
最稳妥的离线方式是把所有 .zip/.tar.gz 包提前下全,再传到目标机。操作分两步:
- 在联网机执行:
composer install --no-install --prefer-dist,这会让 Composer 把所有包缓存到~/.composer/cache/files/ - 用
composer archive或手动打包:tar -czf deps.tgz ~/.composer/cache/files/ - 目标机上先清空缓存:
composer clear-cache,再解压到相同路径:tar -xzf deps.tgz -C ~ - 最后运行:
composer install --no-interaction,Composer 就会从本地缓存读取,不再联网
注意:~/.composer/cache/files/ 下的目录结构是 vendor/name/version-hash/,文件名含哈希,不可手动改名;且该方式对含 git 仓库源的包无效(需改用 --prefer-dist 强制走 zip)。
真正麻烦的从来不是“有没有网”,而是哪些环节看似离线却仍偷偷联网——比如插件、脚本、全局 repo 配置、source 类型依赖。这些点一旦漏掉一个,composer install 就会在你最没防备的时候卡住或报错。


















