离线安装 Composer 依赖必须设 COMPOSER_DISABLE_NETWORK=1 并执行 composer install --no-plugins --no-scripts --no-autoloader,再运行 composer dump-autoload -o;仅拷贝 composer.lock 会因远程元数据校验失败报 “Package not found”,vendor 存在仍报错是因默认访问 packagist.org 校验,未禁网络则任何 --no-xxx 参数均无效。

离线安装 Composer 依赖,不能只拷 composer.lock 就跑 composer install——它大概率报 Package not found 或静默跳过,根本原因是默认仍要校验远程元数据,哪怕 vendor/ 已存在。
为什么 vendor 存在却还报 “Package not found”
这不是文件缺失,而是 Composer 在 install 阶段仍会尝试访问 packagist.org 获取包元数据(如版本列表、dist URL 格式),哪怕最终不下载。只要没显式禁用网络,这个 HTTP 请求就会触发。
-
COMPOSER_DISABLE_NETWORK=1是必须项,否则任何--no-xxx参数都拦不住初始校验 - 若
composer.lock里某个包的dist.url是https://开头,且没配本地仓库,COMPOSER_DISABLE_NETWORK=1下会直接退出 - 验证是否真离线:临时加
127.0.0.1 packagist.org到/etc/hosts,再跑composer install -v,看到Connection refused才算到位
离线安装唯一可靠命令组合
目标机上执行这行命令是目前最稳的落地方式,前提是已有完整 vendor/ 和未改动的 composer.lock:
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
COMPOSER_DISABLE_NETWORK=1 composer install --no-plugins --no-scripts --no-autoloader
-
--no-plugins:跳过插件初始化(很多插件会隐含联网校验) -
--no-scripts:防止post-install-cmd等脚本调用外部工具或 API -
--no-autoloader:避免 autoloader 生成阶段因路径变更或旧缓存触发异常类加载 - 执行完必须补一记:
composer dump-autoload -o,强制刷新 autoload 映射,否则可能运行时报Class not found
预下载依赖到缓存才是可迁移的离线方案
只拷 vendor/ 目录看似简单,但跨系统(Windows/macOS/Linux)、跨 PHP 编译选项、符号链接失效、installed.json 含绝对路径等问题会让它在目标机上静默失败。真正可复用的是 Composer 自己管理的缓存目录。
- 缓存位置由
composer config --global cache-dir决定,默认 Linux/macOS 是~/.composer/cache - 在联网机完整执行一次
composer install --prefer-dist,确保所有包以 ZIP 形式进缓存 - 打包整个
cache/目录(含files/、repo/、archived/),复制到离线机 - 离线机先设环境变量:
COMPOSER_CACHE_DIR=/path/to/your/cachedir,再运行composer install --no-interaction --prefer-dist - 注意两端
composer --version最好一致,不同大版本缓存格式可能不兼容
私有包和 platform 不兼容是静默失败重灾区
离线时最危险的不是报错,而是“看起来成功了,运行时报 Class not found”。这类问题往往源于 composer.lock 里写了不兼容的约束,而 Composer 默认跳过、不提醒。
- 检查
composer.json中"config": {"platform": {...}}是否与目标机 PHP 版本、扩展匹配(比如锁文件里某包 requirephp >=8.2,而离线机只有 8.0,它会跳过安装但不报错) - 私有 Git 包必须提前转成
path或artifact类型仓库,否则离线机无法解析git@或https://gitlab.example.com地址 -
composer validate --no-check-publish要跑一遍,确认锁文件没被手动编辑污染










