离线使用 Composer 必须设置 COMPOSER_DISABLE_NETWORK=1,清理全局镜像和代理配置,确保 composer.lock 仅含 dist 来源,并强制使用 --no-plugins --no-scripts --no-autoloader 参数。

COMPOSER_DISABLE_NETWORK=1 没设,一切离线配置都白搭
离线模式下还报 Curl error 60、Could not resolve host 或 Could not fetch packages.json,99% 是因为漏设了环境变量。Composer 不会因断网自动降级,它坚持要连 https://repo.packagist.org/packages.json,直到硬性失败。
必须提前设置:
- Linux/macOS:
export COMPOSER_DISABLE_NETWORK=1 - Windows CMD:
set COMPOSER_DISABLE_NETWORK=1 - PowerShell:
$env:COMPOSER_DISABLE_NETWORK="1"
这个变量必须在运行 composer install 前生效,且对所有子命令(包括插件调用)起作用。临时加在命令前(如 COMPOSER_DISABLE_NETWORK=1 composer install)在某些 shell 下可能不生效,建议写进 shell 配置或 CI 脚本开头。
全局镜像残留导致 fallback 联网
即使设了 COMPOSER_DISABLE_NETWORK=1,如果全局配置里还留着私有源或旧镜像,Composer 会在离线时尝试 fallback 连接——不是跳过,而是直接报错退出。
检查并清理:
- 运行
composer config -g repo.packagist,若输出非false(比如https://mirrors.aliyun.com/composer/),立刻执行:composer config --global repo.packagist false - 检查是否误配了其他仓库:
composer config --global --list | grep repositories,有就用composer config --global --unset repositories清掉 -
composer config -g secure-http输出true是正常的,它不影响离线逻辑;但composer config -g http-proxy等代理项也建议清空,避免干扰
锁文件含 source 字段,离线必挂
composer.lock 里只要有一条包的 "source": {"type": "git", ...} 或 "dist": {"reference": "..."} 指向远程 Git 仓库,composer install 就会试图校验 commit 或下载 zip,离线环境下必然失败。
这类锁文件天生不支持离线。应对方式只有两个:
- 重生成锁文件:在有网、干净环境中,确保所有依赖都走
dist(即压缩包),运行composer update --prefer-dist --no-dev后提交新composer.lock - 手动编辑锁文件:删掉所有
source块,把对应包的dist.url改成本地路径(如file:///path/to/pkg.zip),但需同步提供该 zip 文件且校验 hash 一致——实操成本高,仅限极端场景
顺带一提:"type": "path" 仓库能离线,但要求路径下有合法 composer.json,且 name 和 version(或 dev- 分支标识)完全匹配锁文件记录。
离线 install 必须带这四个 flag
--no-plugins --no-scripts --no-autoloader 不是可选项,是防踩雷的底线组合。缺一个,都可能触发隐式联网:
-
--no-plugins:防止phpstan/extension-installer等插件在初始化阶段查远程 registry -
--no-scripts:屏蔽post-install-cmd,避免脚本里写了curl或file_get_contents("https://...") -
--no-autoloader:绕过 autoload 重建,某些自定义 autoloader 实现会动态 require 远程类(尤其测试框架里常见)
执行完必须立刻补:composer dump-autoload -o。否则运行时大概率报 Class not found——因为 --no-autoloader 跳过了这步,而优化后的 autoloader(-o)又依赖 vendor 结构已就位。
真正麻烦的点不在命令本身,而在于:你得确认整个依赖树里没藏任何“看起来离线、实则偷偷联网”的行为。比如某个 dev-require 的工具包,它的 post-install 脚本里调了 GitHub API;这种问题不会报错,只会让部署卡在某台机器上,半天才暴露。


















