composer无真正离线模式,本质是禁用网络触发点;最稳命令为composer install --no-plugins --no-scripts --no-autoloader,前提需vendor完整、lock文件匹配、php环境一致,且不可执行update。

Composer 没有真正的“离线模式”,所谓离线,本质是绕过所有网络触发点,靠文件系统和预生成元数据驱动 install 流程。 它不接受临时断网、不兼容半成品状态——vendor 缺一个文件、composer.lock 少一行 dist.shasum、PHP 版本差一个小版本,都可能在内网服务器上突然报 Package not found 或 Could not fetch https://repo.packagist.org/packages.json。
composer install --no-plugins --no-scripts --no-autoloader 是最稳的离线命令
这个组合不是“可选优化”,而是离线场景下防止意外联网的硬性防护。它跳过三类高风险环节:
-
--no-plugins:避免插件(如composer-asset-plugin)初始化时尝试访问 GitHub 或 CDN -
--no-scripts:屏蔽post-install-cmd等脚本,防止它们调用外部 API 或下载额外资源 -
--no-autoloader:跳过自动加载器重建——某些自定义 autoloader 实现会隐式触发远程类查找(极少见但真实存在)
前提条件很明确:vendor 目录必须完整存在,且与 composer.lock 中记录的每个包路径、版本、shasum 严格一致。执行前建议先运行 ls -la vendor/ | head -20 看是否明显缺失目录。
COMPOSER_DISABLE_NETWORK=1 不等于离线安全
设了这个环境变量,composer install 仍可能失败,常见原因有:
-
composer.json里写了"repositories": [{"type": "packagist", "url": false}]—— 这种写法在COMPOSER_DISABLE_NETWORK=1下会直接报错退出,不是静默忽略 - 全局配置里还留着
repo.packagist,哪怕项目级已禁用,Composer 仍会 fallback 并触发校验 - 某个依赖在
composer.lock中标记为"source"类型(比如用了"dev-master"或 Git URL),这种无法走 dist 缓存,离线时无 ZIP 可校验
真正有效的禁用方式只有一种:composer config --global repo.packagist false,再配合项目级 composer config repository.my-local composer https://intranet/packagist/。
复制 vendor 目录比跑 install 更可靠
如果你只是部署固定版本,别折腾 install 命令。直接把外网机器上已验证可用的 vendor/ 和 composer.lock 整体拷到内网机,然后:
- 确认 PHP 版本、必需扩展(
mbstring、openssl、zlib)完全一致 - 入口文件中显式 require:
require '/opt/myapp/vendor/autoload.php';,不依赖当前工作目录 - 若类加载失败,优先运行
composer dump-autoload --classmap-authoritative,而不是重装
注意:不要在已有 vendor/ 的情况下再执行 composer install —— 它会校验锁文件与现有文件的一致性,一旦发现偏差(比如少了一个 vendor/composer/installed.json),就可能触发回退逻辑并报错。
离线环境下不能更新 lock 文件
composer update 在 COMPOSER_DISABLE_NETWORK=1 下必然失败,这不是 bug,是设计使然。所谓“离线更新”,实际是两台机器协作:
- 在开发机(PHP 环境一致)上跑
composer update,生成新composer.lock - 把新
composer.lock和对应 ZIP 包(从~/.composer/cache/files/按 hash 提取)一起拷到内网机 - 内网机只运行
composer install --no-plugins --no-scripts,且必须确保composer.lock中所有dist.url都指向本地file:///路径
最容易被忽略的一点:composer.lock 里的 dist.shasum 必须和你提供的 ZIP 文件实际哈希值完全一致,差一个字节就会校验失败,且不会提示具体哪个包出问题。











