OpenSCA 常识小课堂开课了!
明天次要介绍基于 composer 包管理器的组件成分解析原理。
composer 介绍
composer 是 PHP 的依赖管理工具。
开发者受到 Node.js 的 npm 及 Ruby 的 bundler 启发,composer 设计上与两者有诸多类似。
composer 的依赖管理文件是 composer.json。开发者能够在 composer.json 中指定每个依赖项的版本范畴或应用 composer require/update/remove ${name} 命令治理依赖项。
如果一个我的项目中存在 composer.json 文件,便能够执行 composer install 命令主动装置以后我的项目所需的依赖项并生成 composer.lock 文件
composer.json 残缺文件构造如下:
{
"name": "cakephp/app",
"type": "project",
"license": "MIT",
"require": {
"php": ">=7.2",
"cakephp/cakephp": "^4.3",
"cakephp/migrations": "^3.2",
"cakephp/plugin-installer": "^1.3",
"mobiledetect/mobiledetectlib": "^2.8"
},
"require-dev": {
"cakephp/bake": "^2.6",
"cakephp/cakephp-codesniffer": "^4.5",
"cakephp/debug_kit": "^4.5",
"josegonzalez/dotenv": "^3.2",
"phpunit/phpunit": "~8.5.0 || ^9.3"
},
}
其中 name 为项目名称;type 为包的类型,有 library、project、metapackage 和 composer-plugin 四种类型,默认状况下为 library;license 为我的项目申明的许可证,能够是一个字符串或是一个字符串数组。
require-dev 为开发环境或测试应用的依赖,require 为生产环境应用的依赖,依赖写法为 ”name”:”version”,版本能够指定精确版本或一个范畴。
解析算法
composer.lock
composer.lock 文件为主动生成的文件,能够精确定位到 PHP 我的项目应用的依赖及版本,所以优先解析 composer.lock 文件。
composer.lock 文件构造如下:
{
"packages": [
{
"name": "a",
"version": "1.1.0",
"require": {"c": "1.1.*"}
},
{
"name": "b",
"version": "1.2.2",
"require": {"c": "^1.0.2"}
},
{
"name": "c",
"version": "1.1.2"
}
],
"packages-dev": []}
其中 packages 和 packages-dev 字段蕴含我的项目应用的所有间接和间接依赖,而且记录了组件间的依赖关系,packages 为生产环境的依赖,packages-dev 为开发环境的依赖。
示例:
{
"name": "a",
"version": "1.1.0",
"require": {"c": "1.1.*"}
}
代表我的项目依赖 1.1.0 版本的组件 a,且该组件依赖版本束缚为 1.1.* 的组件 c。
同理可知我的项目依赖 1.2.2 版本的组件 b,且该组件依赖版本束缚为 ^1.0.2 的组件 c。
且组件 a 和组件 b 都没有被其余依赖所依赖,所以可知这两个组件是我的项目的间接依赖。
注:
1.1.* 代表版本号须要 >=1.1.0 且 <1.2.0
^1.0.2 代表版本号须要 >=1.0.2 且 <2.0.0
由此能够构建出以后我的项目的依赖构造:
实线代表间接依赖,虚线代表间接依赖
composer.json
composer.json 为开发者治理的依赖管理文件,在未找到 composer.lock 文件时将解析该文件。
composer.json 仅蕴含间接依赖,在我的项目构建时会从 composer 仓库下载须要的间接依赖并构建为 composer.lock 文件,因而能够模仿 composer 构建流程来获取我的项目援用的组件依赖。
composer.json 文件构造如下:
{
"name": "foo",
"type": "project",
"license": "MIT",
"require": {
"a": "^1.1.0",
"b": "^1.2.0",
},
"require-dev": {},}
require 为我的项目理论应用的间接依赖,require-dev 为我的项目开发时应用的间接依赖。
例如:
“a”: “^1.1.0″ 代表我的项目依赖版本束缚为 ^1.1.0 的组件 a。
“b”: “^1.2.0″ 代表我的项目依赖版本束缚为 ^1.2.0 的组件 b。
剖析到这里咱们能够总结出如下图依赖关系:
实线代表间接依赖
通过该依赖关系能够看出我的项目组件的间接依赖及组件的版本范畴,但无奈得悉组件依赖的具体版本。
在没有 composer.lock 文件的状况下,为了进一步获取依赖的精确版本及间接依赖,须要从 composer 仓库下载对应组件的详细信息。
例如组件 a 的详细信息构造为:
{
"packages": {
"a": [
{
"version": "1.0.1",
"require": {"c": "^1.0.0"}
},
{
"version": "1.1.0",
"require": {"c": "^1.1.0"}
}
]
}
}
其中 packages 字段为组件及各个版本信息的映射,require 字段为组件的依赖信息。
对于本例来说,组件 a 的束缚为 ^1.1.0,要求版本号 >=1.1.0 且 <2.0.0,所以抉择 1.1.0 版本。
因而组件依赖构造就变成了:
依照这种形式层级解析便可获取整个我的项目的依赖信息。
感激每一位开源社区成员对 OpenSCA 的反对和奉献。
OpenSCA 的代码会在 GitHub 和 Gitee 继续迭代,欢送 Star 和 PR,成为咱们的开源贡献者,也可提交问题或倡议至 Issues。咱们会参考大家的倡议不断完善 OpenSCA 开源我的项目,敬请期待更多功能的反对。
OpenSCA 官网:
https://opensca.xmirror.cn/
GitHub:
https://github.com/XmirrorSecurity/OpenSCA-cli/releases
Gitee:
https://gitee.com/XmirrorSecurity/OpenSCA-cli/releases