离线仓库必须用artifact或path类型,且全局及项目级packagist.org必须彻底禁用,否则仍会发DNS请求;artifact要求.tar.gz命名严格为vendor-name/package-name-version.tar.gz,内部composer.json的name和version须与文件名完全一致,所有包平铺于同一目录;path仓库需配置type为"path"、url为合法本地路径、require时加@dev,且Windows需显式启用symlink。

离线仓库不是“配个地址就行”,必须用 artifact 或 path 类型,且全局和项目级的 Packagist 必须彻底禁用——否则 composer install 仍会发 DNS 请求或报 404。
为什么 composer config repositories.offline 配了还连网?
根本原因是 Packagist 的 fallback 行为没关干净:
- 必须执行
composer config --global repo.packagist false(全局关) - 再检查项目级:运行
composer config repo.packagist,输出必须为空;如果返回composer https://packagist.org,说明项目composer.json的repositories里还留着 Packagist 条目,得手动删掉 - 验证是否真离线:加
-v运行composer install,全程不能出现Downloading https://repo.packagist.org/...或任何DNS lookup日志
artifact 仓库怎么建才真正离线?
artifact 是唯一零网络探测的类型,但包命名和结构有硬约束:
- 所有
.tar.gz文件必须按vendor-name/package-name-version.tar.gz命名,例如monolog/monolog-2.13.0.tar.gz - 每个压缩包内必须含有效
composer.json,其中name和version字段要与文件名完全一致(大小写、分隔符都不能错) - 所有包放在同一级目录下(如
/opt/artifacts/),不能嵌套子目录 - 配置命令是:
composer config repositories.offline '{"type":"artifact","url":"/opt/artifacts/"}' -
composer install会严格按composer.lock中的dist.shasum查找并校验文件,失败直接中断,不 fallback
path 仓库用于本地开发,但 Windows 和 ThinkPHP 有坑
path 类型跳过网络请求,但只读取本地目录的 composer.json,对路径和配置极其敏感:
- 必须写进项目根目录的
composer.json的repositories数组里,type小写严格为"path"(写成"Path"静默失败) -
url推荐相对路径,如"./packages/my-utils";Windows 下若要用绝对路径,得用正斜杠"C:/dev/my-utils"或双反斜杠"C:\dev\my-utils" - 本地包的
composer.json必须有合法name(格式vendor/name,全小写无空格)和version(如"dev-main") - require 时必须加开发版约束:
"my-utils/my-utils": "dev-main"或"my-utils/my-utils": "@dev",否则 Composer 不识别 - Windows 默认禁用符号链接,需在
repositories里显式加"options": {"symlink": true},否则改本地代码不会实时生效
离线部署时最容易忽略的三个点
很多团队卡在最后一步,不是因为仓库没配好,而是环境细节没对齐:
-
composer.phar必须从同 PHP 版本的联网机生成并拷贝,离线机上php -v和构建机必须一致,否则autoload可能失效 - 离线安装依赖前,
vendor/目录必须清空,composer.lock必须存在且完整——没有 lock 文件,composer install在离线模式下直接报Could not find package - ThinkPHP 项目不能在
vendor/或全局配置path仓库,所有repositories必须显式写在项目根目录composer.json中,漏掉这一条,composer require就永远找不到包











