Composer require 命令必须联网,不查本地缓存;离线安装唯一可靠方式是:有网机上编辑 composer.json + composer update 某包 → 打包含 composer.lock 和 vendor 的完整目录 → 离线机设 COMPOSER_DISABLE_NETWORK=1 后执行 composer install --no-interaction --no-plugins --no-scripts --no-dev。

无网络时执行 composer require 会直接报错,不是“走缓存”,而是根本不会触发缓存查找
Composer 的 require 命令默认行为是联网解析依赖树、校验版本约束、下载新包并更新 composer.lock。它**不检查本地缓存是否已有对应 ZIP**,也不尝试复用 ~/.composer/cache/files/ 中的文件。一旦 DNS 失败或 HTTP 请求超时,就会立刻中断并抛出 Could not fetch packages 或 Connection refused 错误。
你看到的“缓存”只在 composer install 阶段参与解压流程,且前提是 composer.lock 已存在、内容完整、所有包的 SHA256 校验值匹配缓存中的 ZIP —— require 不满足这个前提。
真正能离线安装依赖的唯一路径:先有 composer.lock + 完整 vendor + 禁用网络
想让新依赖“看起来像被 require 过”,必须绕过 require 命令本身,改用预生成方式:
- 在有网机器上,先手动编辑
composer.json,追加你要的"vendor/package": "^x.y" - 运行
composer update vendor/package --no-dev --prefer-dist --no-scripts --no-plugins(确保不触发任何网络外行为) - 确认
vendor/和composer.lock都已更新完成,再打包整个项目目录(含composer.json、composer.lock、vendor/) - 离线机上,设置环境变量
COMPOSER_DISABLE_NETWORK=1,再执行composer install --no-interaction --no-plugins --no-scripts --no-dev
注意:--no-plugins 和 --no-scripts 是关键,否则某些插件(如 symfony/flex)仍会尝试联网拉 recipe 或触发 npm install。
为什么不能只拷 ~/.composer/cache/files/ 过去?
因为缓存 ZIP 文件没有元数据绑定,Composer 离线时无法知道该 ZIP 对应哪个包、哪个版本、是否满足当前 composer.json 的约束。它需要 composer.lock 提供精确的 dist.url 和 dist.shasum,才能定位并校验缓存中是否存在可用 ZIP。
即便你把整个 ~/.composer/cache/ 拷过去,离线执行 composer install 时仍会卡在 Reading packages.json from cache —— 因为 repo/ 子目录里没有 packages.json 元数据,而这些数据只能从 Packagist 或镜像源实时拉取。
常见误操作:
- 只拷
vendor/但漏掉composer.lock→install会报Lock file does not contain required package - 拷了
lock但没清掉离线机上旧的vendor/→ 可能混入不匹配版本,autoload 失效 - 没设
COMPOSER_DISABLE_NETWORK=1→ Composer 仍会尝试发起 HEAD 请求探测源站,导致超时卡死
临时补救:用 composer install --no-cache 强制重走网络?不行,它更依赖网络
--no-cache 的作用是跳过本地缓存,**强制所有包都重新下载**——这在离线环境下等于主动要求失败。它不仅不会帮你利用已有 ZIP,反而会禁用 files/ 缓存路径,让 Composer 完全失去 fallback 能力。
如果你发现离线机上 vendor/ 缺一个包,又没法连网,唯一安全做法是回到有网机器,用相同 PHP 版本和 Composer 版本(建议 composer self-update --2 统一到 2.x),补全那个包后重新打包。不要试图在离线机上手动解压 ZIP 到 vendor/,因为 autoload 生成、bin 符号链接、post-install-cmd 脚本都不会自动执行,后续大概率运行时报 Class not found 或 Command not found。


















