离线环境必须用composer install --no-dev而非update,因update需联网拉取元数据和包信息而必然失败;install仅按composer.lock还原本地缓存或预装的依赖,不发起HTTP请求,前提是lock文件存在且完整、PHP版本与扩展一致。

离线环境必须用 composer install --no-dev 而不是 composer update
离线时没有网络,composer update 会直接失败——它要连 Packagist 或自定义镜像拉取最新元数据和包信息。真正能用的只有 composer install,前提是项目已有 composer.lock,且所有依赖包已提前下载并缓存到位。
关键点在于:composer install 只读 composer.lock 中记录的精确版本和哈希值,然后从本地 cache 或指定安装源还原 vendor,不发起任何 HTTP 请求。
- 确保
composer.lock已提交进 Git(很多人忽略这点,导致离线机上 lock 文件缺失或过期) - 不要在离线机上手动删
vendor/后又没备份composer.lock—— 那等于没锁 -
--no-dev是安全习惯:跳过require-dev里的包(如 PHPUnit、PHPStan),减少离线部署体积和兼容风险
提前备份 vendor 目录本身最简单,但要注意路径和权限
直接打包整个 vendor/ 目录到离线环境,是最快落地的方案,适合内网交付、嵌入式 PHP 环境或 CI/CD 构建机隔离场景。但它不是“标准 Composer 流程”,需人工保证一致性。
- 备份前运行
composer install --no-dev --optimize-autoloader,生成优化后的vendor/autoload.php和类映射 - 压缩时保留 Unix 权限(
tar -czf vendor.tgz vendor/),否则解压后autoload_static.php可能因执行权限缺失报错 - 目标机器 PHP 版本、扩展(如
mbstring、json)必须与构建机一致,否则某些包(如symfony/polyfill)运行时行为不同
用 composer archive 打包单个包不解决 vendor 离线问题
composer archive 只能导出某个已安装包的源码 ZIP,比如 composer archive monolog/monolog 2.10.0,但它不包含依赖树、自动加载配置或 autoload-dev 规则。你没法靠一堆零散 ZIP 拼出可用的 vendor/。
真正需要的是完整依赖快照,而不是单包归档:
- 别用
composer archive做离线 vendor 备份 - 想分发单个组件?改用
git subtree或发布私有 ZIP 包到内网 HTTP 服务器,再配repositories类型为package - 如果非要用 archive,至少配合
--format=zip --dir=dist/输出,并手动生成composer.json描述其 autoload 规则
私有 Packagist + composer config --global repo.packagist composer https://your-mirror/ 是长期方案
如果你有稳定内网环境,搭建一个私有 Packagist(如 Satis 或 Private Packagist)并同步所需包,才是可维护的离线策略。此时 composer install 仍走 HTTP,但流量完全在内网闭环。
- 首次同步需联网,之后所有
composer install都走内网,速度更快、更可控 - 必须配置
composer config --global repo.packagist composer https://your-mirror/,否则默认仍尝试访问 packagist.org - Satis 静态生成 JSON,适合只读场景;Private Packagist 支持 Webhook 自动同步,但需付费
- 注意 mirror 的
allow-plugins和minimum-stability配置要与线上一致,否则某些包会被跳过
最容易被忽略的一点:离线环境中 composer install 成功不代表应用能跑。务必验证 vendor/autoload.php 是否可 require,以及核心服务(如数据库连接、日志初始化)是否触发了未打包的 polyfill 或运行时扩展依赖。











