离线时“Package not found”主因是元数据缺失而非网络问题;需确保packages.json含目标包、dist.shasum一致、禁用Packagist(repo.packagist设为false)、启用COMPOSER_DISABLE_NETWORK=1,并通过path仓库安全添加新包。

离线时“Package not found”不是网络问题,而是元数据缺失
报错 Could not find package foo/bar 在离线环境下几乎从不因为“连不上”,而是因为 Composer 根本没拿到这个包的元数据——它不知道该包存在、有哪些版本、dist URL 是什么。即使 vendor/ 里已有对应目录,只要 composer.lock 中记录的包没在本地仓库或缓存中注册,install 就会失败。
关键点在于:Composer 离线运行时依赖两类元数据源:packages.json(描述所有包的索引)和 dist.shasum(校验用哈希)。缺一不可。
- 若用 Satis 构建镜像,必须确保
packages.json文件已生成且包含目标包(含全部子依赖,如psr/log、symfony/polyfill-ctype) - 若靠缓存迁移,
~/.composer/cache/files/下必须有完整路径:foo/bar/abc123def4567890.zip,文件名哈希必须与composer.lock中dist.shasum完全一致 - 运行
composer diagnose可验证是否加载了自定义仓库;若输出里没有你的packages.json地址,说明配置未生效
禁用 Packagist 是硬性前提,不是可选项
哪怕你只配了一个私有仓库,只要没显式关掉默认源,Composer 仍会在 install 阶段尝试请求 https://repo.packagist.org/packages.json,然后直接报 Connection refused 并退出——它不会 fallback 到你配的源。
必须执行:
composer config --global repo.packagist false
注意:false 是字面量,不是字符串;不能写成 "false" 或 0。这条命令会写入 ~/.composer/config.json 的 repositories 段,覆盖掉默认的 packagist.org 条目。
- 如果项目级
composer.json里还写了"repositories": [{"type":"packagist", "url": "https://..."}],必须删掉或改为{"type":"packagist", "url": false} -
COMPOSER_DISABLE_NETWORK=1环境变量也得设,否则某些插件(如composer/installers)仍可能触发 DNS 查询 - 设完后跑
composer config --list | grep repo,确认输出中只有你配的源,且repo.packagist显示为false
子依赖缺失比主包更难发现
常见现象是:主包(如 monolog/monolog)能装上,但运行时报 Class not found: Psr\Log\LoggerInterface。这是因为 psr/log 是它的子依赖,而你在联网机执行 composer install 时没触发完整安装流程,导致该包没进缓存,也没被写入 vendor/。
根本原因:子依赖是否被拉取,取决于你当时用的命令和参数。
- ❌ 错误做法:
composer require monolog/monolog—— 只拉主包,子依赖可能走 lazy load,不进缓存 - ✅ 正确做法:
composer install --no-dev --prefer-dist(在联网机完整执行),确保composer.lock中所有条目都被解析并缓存 - 验证方式:检查
composer.lock中packages数组长度,再对比~/.composer/cache/files/下目录数;两者应基本一致(允许极少数 dev-only 包差异)
新增包只能走 path 仓库,别碰 require
离线环境不能执行 composer require,因为它必须联网查包名合法性、版本可用性、依赖树兼容性。唯一安全的添加方式是把本地目录当包源用。
操作要点:
- 目标包根目录下必须有合法
composer.json,含"name"(如"acme/utils")、"version"(如"1.2.3")或"minimum-stability": "dev"+"prefer-stable": true - 项目根目录
composer.json中添加:"repositories": [{"type":"path","url":"./packages/acme-utils"}](注意是相对路径,且不能以/开头) - 然后运行:
composer require acme/utils --no-update(先写入 lock),再composer update acme/utils --no-install --no-plugins --no-scripts(只更新 lock 不下载) - 最后在离线机执行
composer install --no-plugins --no-scripts,Composer 会自动从./packages/acme-utils复制代码,不联网
最易忽略的是:path 仓库里的包,其 autoload 规则必须正确,否则 composer dump-autoload -o 无法生成对应映射——这会导致 Class not found,且错误发生在运行时,而非 install 阶段。











