artifact仓库只认包含多个zip的目录路径,不认单个zip文件路径;zip必须按{vendor}/{package}-{version}.zip命名,解压后composer.json需与文件名严格一致,且仅支持语义化版本号。

artifact仓库只认目录,不认zip文件路径
你不能在repositories.url里写./packages/mylib-1.2.0.zip——这会直接报错Invalid repository type "artifact"。artifact类型只接受一个**包含多个zip文件的目录路径**,且该路径必须是zip文件的父目录,结尾不能带/。
正确做法是把所有zip放进./packages/,然后配置:
{
"repositories": [
{
"type": "artifact",
"url": "./packages"
}
]
}
常见错误:误把url设为./packages/(末尾斜杠)或./packages/mylib-1.2.0.zip(指向文件),都会导致Composer静默跳过该仓库。
zip包命名和内部结构必须严格匹配
artifact仓库不读取zip里的composer.json来推导包名,而是靠**文件名反向解析**。它期望每个zip按{vendor}/{package}-{version}.zip格式命名,例如monolog/monolog-2.10.0.zip。
- 文件名中
monolog/monolog会被当作name字段值,2.10.0被当作version - zip解压后根目录下必须有
composer.json,且其中"name"和"version"必须与文件名完全一致 - 不支持
dev-main、dev-develop这类分支别名——version必须是明确语义化版本号 - 压缩包里不能有多余外层目录(比如
mylib-1.2.0/composer.json不行,必须是composer.json在根)
require时写包名,不是文件路径
执行composer require时,参数只能是vendor/name形式,比如monolog/monolog,绝不能写./packages/monolog-2.10.0.zip——后者会触发Could not find a matching version of package ./packages/...。
版本约束也得匹配文件名中的版本:
- 如果zip叫
acme/utils-1.2.0.zip,就只能composer require acme/utils:^1.2或acme/utils:1.2.0 -
^1.2不会自动匹配1.2.1,除非你真放了个acme/utils-1.2.1.zip - 运行
composer update acme/utils才会重新扫描./packages/目录;composer install只按composer.lock安装,不会刷新可用版本
离线环境必须用同一份配置生成lock
artifact仓库生效的前提是composer.lock里记录的dist URL已被替换为本地路径。如果你先在线执行composer install生成lock,再切到离线机器改repositories,lock文件仍指向Packagist,安装会失败。
正确流程:
- 在联网机器上,先配好
artifact仓库并写入composer.json - 运行
composer install --no-dev生成含本地dist信息的composer.lock - 把整个项目(含
composer.json、composer.lock、./packages/)打包带到离线机器 - 离线机上直接
composer install即可,无需网络
最容易被忽略的是:artifact不校验内容一致性,只依赖文件名和lock记录。一旦zip内容变了但文件名没改,Composer就完全感知不到——你得手动删vendor/和composer.lock重装。











