离线添加新包必须手动补全composer.json、复制包代码到vendor/并执行composer dump-autoload -o;依赖版本号须与实际代码一致,且必须同步更新composer.lock中对应条目及dist.shasum。

离线环境下不能用 composer require
因为 composer require 默认会联网查询包元数据、校验版本可用性、下载 dist 包,即使 COMPOSER_DISABLE_NETWORK=1 已设,它也会直接报错退出(不是静默跳过)。你看到的错误通常是:Could not fetch https://repo.packagist.org/packages.json 或 Failed to decode response: zlib_decode(): data error——这不是网络抖动,而是 Composer 在启动阶段就强制发起元数据请求,根本没走到“是否能装”的逻辑。
所以离线添加新包,必须绕过 require 的自动解析流程。核心思路是:手动补全 composer.json + 手动提供包代码 + 强制重建 autoload。
- 先在联网环境准备好目标包的完整 dist ZIP(从 packagist 页面下载,或从另一台已安装的机器提取
vendor/vendor/package/目录) - 把包目录(如
monolog/monolog)整个复制进本地vendor/,路径必须与命名空间一致 - 手动编辑
composer.json,在require里加一行:"monolog/monolog": "3.8.0"(版本号必须和你复制进来的实际代码完全一致) - 运行
composer dump-autoload -o,不加-o可能漏掉 classmap 或 PSR-4 映射
composer.json 里写 "repositories" 在离线时会直接失败
很多人想靠配置本地 artifact 或 path 仓库来“模拟”在线源,但这是高危操作。比如写成:
"repositories": [
{
"type": "artifact",
"url": "./packages/"
}
]
问题在于:composer install 或 dump-autoload 仍会尝试读取该目录下所有 .zip 文件的 composer.json 元数据,并校验 dist.shasum;如果 ZIP 包不完整、哈希不匹配、或里面嵌套了其他未提供的子依赖,就会卡住或报 Invalid package information。
更糟的是,若用了 "type": "path",Composer 会尝试执行 symlink(Linux/macOS)或 copy(Windows),而 symlink 在某些 CI 环境或容器中被禁用,导致 Class not found。
真正稳的做法只有两个:
- 用
path仓库,但只指向已验证可运行的本地开发包目录(非 dist ZIP),且确保该目录含完整composer.json和可 autoload 的结构 - 彻底不用
repositories,改用「预打包 vendor + 手动 patch」:即在联网机上跑composer require vendor/package,再把整块vendor/vendor/package和更新后的composer.lock一起拷过来
补丁包必须同步更新 composer.lock,否则 install 会校验失败
离线机上哪怕 vendor/ 里已有新包目录,只要 composer.lock 没记录它,下次执行 composer install 就会删掉这个“非法”目录——因为 Composer 把 lock 当作唯一权威,vendor/ 只是缓存产物。
所以补丁流程缺一不可:
- 在联网环境执行
composer require vendor/package(生成正确 lock 条目) - 用
git diff composer.lock提取新增的包段落(含name、version、dist哈希、source类型) - 把这段 JSON 手动合并进离线机的
composer.lock(注意逗号和缩进,JSON 格式错一个字符就整个 lock 失效) - 确认
composer.lock中该包的dist.shasum和你复制进vendor/的实际 ZIP 或目录内容一致(可用sha256sum vendor/vendor/package/composer.json快速比对关键文件)
最容易被忽略的一点:如果新包本身有 require-dev 或 bin 脚本,这些不会进 lock,但可能影响运行时行为——离线补丁只解决“能装”,不保证“能跑”。


















