composer licenses 仅输出项目自身 license 字段,不扫描依赖;应使用 composer show --licenses 遍历 vendor 获取全量依赖许可证,注意其不校验 spdx 合规性且需先安装依赖。

别用 composer licenses 查依赖协议——它在 Composer 2.2+ 中存在,但只输出你项目自身的 license 字段,比如 myapp/myproject → MIT,一行,仅此而已。真要扫全量依赖的许可证,必须用 composer show --licenses。
为什么 composer licenses 不是你要找的命令
它不读 vendor/,不解析 composer.lock,也不递归检查任何依赖。哪怕你刚跑完 composer update,装了 200 个包,composer licenses 的输出也不会多出一个字符。官方文档没写清楚这点,加上命令名带 “licenses”(复数),很多人误以为它能“一键汇总”,结果法务审核时发现 guzzlehttp/guzzle、symfony/console 等关键依赖压根没被查过。
常见错误现象:
-
composer licenses输出为空或只有单行,以为环境异常,其实是命令本身就不该这么用 - 加了
--no-dev或--format=json仍无变化——参数对单行输出无效 - 旧教程里写的
--recursive在 Composer 2.5+ 已移除,且从未真正支持过递归扫描
composer show --licenses 才是真正可用的原生命令
这是目前 Composer 官方唯一稳定、覆盖全部已安装包的许可证查看方式(2.1.12+ 起可用)。它会遍历整个 vendor/ 目录,读取每个包的 composer.json,提取 name、version、license 字段。
实操要点:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 必须先执行过
composer install或composer update,否则vendor/为空,命令直接失败 - 加
--no-dev排除require-dev中的包(如phpunit/phpunit),避免把测试工具的 GPL 协议误计入生产合规范围 -
--format=json输出结构化数据,但注意:license字段可能是字符串("MIT")、数组(["MIT", "Apache-2.0"])、null,甚至 URL("https://example.com/LICENSE"),脚本解析时得兼容 - 不支持
--tree参数查依赖层级——它只列扁平列表,不展开传递依赖
看到 "MIT" 就放心?这些坑最常被跳过
composer show --licenses 只照搬 composer.json 里的 license 字段,不做任何校验。它不读真实 LICENSE 文件,不比对 SPDX 标准,也不管作者有没有漏传许可文本。
典型误判场景:
- 某个包声明
"license": "MIT",但 tarball 里根本没LICENSE文件,或混入了 GPL 源码——命令完全不报错 -
"license": ["MIT", "BSD-3-Clause"]✅,但写成["MIT", "BSD 3 Clause"]❌(空格/大小写/拼写偏差导致 SPDX 解析失败) -
license字段为"proprietary"、"unlicensed"、null或空字符串——这类包法律风险极高,法务通常直接叫停上线 - 遇到
GPL-2.0-only和GPL-2.0-or-later,命令输出一样,但法律效力完全不同,必须人工核对源码仓库 tag 下的原始声明
CI 和自动化中怎么安全用
想在 CI 流水线里卡住高风险协议?别只靠 composer show --licenses,它只是起点。推荐组合:
- 导出 JSON 后用
jq过滤:composer show --no-dev --format=json | jq -r '.[] | select(.license == null or (.license | type == "string" and (.license | test("GPL|AGPL|proprietary"; "i"))) or (.license | type == "array" and (.[] | test("GPL|AGPL|proprietary"; "i")))) | .name' - CI 中硬检查(只允许白名单):
composer show --no-dev --format=json | jq -r '.[].license // ["UNLICENSED"] | .[]' | grep -qE '^(MIT|Apache-2.0|BSD-3-Clause)$' || (echo "non-compliant license found"; exit 1) - 不想装完整
vendor/?直接解析composer.lock:jq -r '.packages[] | "\(.name)\t\(.version)\t\(.license // ["unknown"] | join(" | "))"' composer.lock,但注意部分嵌套依赖可能漏报
最易被忽略的一点:你改自己项目的 composer.json 里的 license 字段,只是更新 Packagist 页面上的徽章,既不控制代码权限,也不影响 composer install 行为——它就是个标签,不是开关。










