最可靠方式是直接复制 vendor 目录,但需源机与目标机 PHP 小版本(如8.2.12)、mbstring/openssl/json/curl扩展及Composer版本完全一致;否则运行时出现Class not found或Extension missing。

直接复制 vendor 目录是最可靠的方式,但前提是源机和目标机的 PHP 小版本(如 8.2.12 vs 8.2.13)、关键扩展(mbstring、openssl、json、curl)和 Composer 版本完全一致;否则 Class not found 或 Extension missing 会在运行时才暴露。
为什么 composer install 在离线机上仍会失败
即使 vendor/ 和 composer.lock 都已存在,composer install 默认仍会尝试联网校验包元数据、触发插件、执行脚本。典型卡点是:Could not fetch https://repo.packagist.org/packages.json 或 Connection refused。这不是“网络不稳定”,而是默认行为无法跳过——除非你切断所有触发路径。
-
COMPOSER_DISABLE_NETWORK=1是硬性前提,不设它,所有--no-xxx参数都无效 - 全局配置残留
repo.packagist会导致 fallback 校验,必须运行composer config --global repo.packagist false -
composer.lock中若含"source"类型条目(如 Git URL 或"dev-master"),离线时无法校验,install 必然失败 - 项目
composer.json里写了"repositories": [{"type": "packagist", "url": false}],在COMPOSER_DISABLE_NETWORK=1下也会直接退出,不是静默忽略
迁移前必须在源机完成的验证动作
别跳过这步:在源机执行完整安装并验证 autoload 是否真正可用。很多“看着 vendor 有文件”但实际跑不起来,是因为 autoload.php 没重建或路径污染。
- 运行
composer install --no-dev --optimize-autoloader - 写最小测试脚本:
require 'vendor/autoload.php'; echo class_exists('Monolog\Logger') ? 'OK' : 'FAIL'; - 确认输出
OK,再打包整个项目目录(含vendor/、composer.lock、composer.json) - 若不确定
vendor/是否干净,可用composer install --no-plugins --no-scripts --no-autoloader --dry-run(Composer 2.5+)预览校验行为
目标机上必须执行的命令组合
离线机不能只跑 composer install,必须用参数强制跳过所有可能联网或破坏环境的动作。以下不是“可选优化”,而是防止失败的强制防护。
- 先清空全局缓存:
composer clear-cache或更彻底地composer config --global cache-dir /dev/null - 执行:
COMPOSER_DISABLE_NETWORK=1 composer install --no-plugins --no-scripts --no-autoloader --no-interaction --no-dev --optimize-autoloader - 最后补一记:
composer dump-autoload -o,修复 symlink 路径污染或权限问题,否则大概率报Class not found - 注意:不要加
--ignore-platform-reqs——它会掩盖扩展缺失问题,让错误延后到运行时才暴露
最容易被忽略的一点:PHP 小版本差异(比如 8.2.12 和 8.2.13)可能导致 vendor/ 中某些类在目标机上解析失败,这种问题不会在 composer install 阶段报错,而是在第一次 require 时才崩溃。务必比对 php -v 输出的完整版本字符串,而不是只看主次版本。











