composer国内源找不到包版本的解决方法

阅读说明

软件版本

  • PHP v8.2.8
  • Composer v2.7.7

问题过程

背景

最近在给Laravel v11.1.4安装依赖的时候遇到如下报错:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Downloading https://mirrors.aliyun.com/composer/p2/fruitcake/php-cors~dev.json if modified

[304] https://mirrors.aliyun.com/composer/p2/fruitcake/php-cors~dev.json

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors~dev.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors~dev.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors~dev.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors~dev.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors~dev.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors~dev.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors~dev.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors.json from cache

Reading /Users/jayce/Library/Caches/composer/repo/https---mirrors.aliyun.com-composer/provider-fruitcake~php-cors~dev.json from cache

Your requirements could not be resolved to an installable set of packages.

  

Problem 1

- laravel/framework[v11.9.0, v11.9.1, v11.9.2] require fruitcake/php-cors ^1.3 -> found fruitcake/php-cors[dev-feat-setOptions, dev-master, dev-main, dev-test-8.2, v0.1.0, v0.1.1, v0.1.2, v1.0-alpha1, v1.0-alpha2, v1.0-beta1, v1.0.0, v1.0.1, v1.1.0, 1.1.x-dev (alias of dev-main), v1.2.0, 1.2.x-dev (alias of dev-master)] but it does not match the constraint.

- Root composer.json requires laravel/framework ^11.9 -> satisfiable by laravel/framework[v11.9.0, v11.9.1, v11.9.2].

说是fruitcake/php-cors的包找不到v1.3.0的版本,laravel/framework依赖了这个包,对应依赖如下:

1
2
3
"require": {
    "fruitcake/php-cors": "^1.3"
}

通过命令进行检查:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
composer show --latest -a fruitcake/php-cors
# 以下为输出结果
name     : fruitcake/php-cors
descrip. : Cross-origin resource sharing library for the Symfony HttpFoundation
keywords : symfony, cors, laravel
versions : dev-master, 1.2.x-dev, v1.2.0, 1.1.x-dev, v1.1.0, v1.0.1, v1.0.0, v1.0-beta1, v1.0-alpha2, v1.0-alpha1, v0.1.2, v0.1.1, v0.1.0, dev-main, dev-test-8.2, dev-feat-setOptions
latest   : v1.2.0 released 2022-02-20, 2 years ago
type     : library
license  : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText
homepage : https://github.com/fruitcake/php-cors
source   : [git] https://github.com/fruitcake/php-cors.git c70ea7b05b9a1b13d3196f235d5995b3deb93ae8
dist     : [zip] https://api.github.com/repos/fruitcake/php-cors/zipball/c70ea7b05b9a1b13d3196f235d5995b3deb93ae8 c70ea7b05b9a1b13d3196f235d5995b3deb93ae8
names    : fruitcake/php-cors

support
issues : https://github.com/fruitcake/php-cors/issues
source : https://github.com/fruitcake/php-cors/tree/master

autoload
psr-4
Fruitcake\Cors\ => src/

requires
php ^7.4|^8.0
symfony/http-foundation ^4.4|^5.4|^6|^7

requires (dev)
phpunit/phpunit ^9
squizlabs/php_codesniffer ^3.5
phpstan/phpstan ^1.4

检查阿里云镜像fruitcake/php-cors包的json,同样也是包的最新版本是v1.2.0(2022-02-20),该包在23年10月12日就发布了v1.3.0的版本,看来是阿里云已经很长时间没更新这个包了。

解决方法一

最简单直接的方式是换源,点我更换镜像源

这里以腾讯云为例:

1
composer config -g repos.packagist composer https://mirrors.tencent.com/composer/

对应~/.composer/config.json配置被修改如下:

1
2
3
4
5
6
7
8
{
  "repositories": {
    "packagist": {
        "type": "composer",
        "url": "https://mirrors.tencent.com/composer/"
    }
  }
}

该方式的缺点是,万一腾讯云也没更新该包的最新版本的话,问题依旧。

解决方法二

阿里云镜像源文档提到了canonical参数,配置如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "repositories": [
    {
      "description": "阿里云镜像",
      "type": "composer",
      "url": "https://mirrors.aliyun.com/composer/",
      "canonical": false
    }
  ]
}

解释是阿里云镜像站下载文件出错(例如404或者超时的情况等)或者包不是最新时,再从官方源上下载,这样确实能够解决阿里云包不是最新的问题。

但这个参数是怎么起作用的?怎么工作的呢?来细细研究一下。

composer在解决包依赖的时候,会从repositories数组中上到下从镜像源中寻找包。

这里还有一个默认行为,packagist.org官方源会被隐式的添加到repositories的最后一个,如果要禁用该行为,设置如下:

1
2
3
4
5
6
7
{
  "repositories": [
    {
      "packagist.org": false
    }
  ]
}

回到正题,canonical参数的官方解释,我大概复述一下,我们所说的镜像,其实在官方是指存储库,即repositories属性中的配置,存储库又分为规范存储库(Canonical repositories)和非规范存储库(repositories non-canonical)。

在composer v2.x的版本中,默认所有存储库都是规范的(即"canonical": true)。

而composer v1.x所有存储库都视为非规范存储库(即"canonical": false)。

规范存储库有两个好处:

  • 性能好,一旦在某个存储库中找到包以后,就会停止去扫描别的存储库去寻找包。
  • 更安全,假设你设置了一个非规范的私有存储库,当你的项目中依赖一个私有包foo/bar ^2.0(假设版本是v2.4.3),之后当有人在packagist.org发布了一个foo/bar v2.999的话,那么composer会读取到该包,因为v2.999的包更新,并且符合^2.0的约束,那么你的项目可能会安装到预期以外的东西。规范存储库就不会有这个问题,因为在规范存储库中找到包以后就不会再去扫描别的存储库了。

解决方法三

正如上面所提到的,设置成非规范存储库是有风险的,并且安装过程会更慢。

解决办法也不是没有,可以多个镜像源混合使用,修改~/.composer/config.json如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "repositories": [
    {
      "type": "composer",
      "url": "https://mirrors.aliyun.com/composer/",
      "exclude": ["fruitcake/php-cors"]
    },
    {
      "type": "composer",
      "url": "https://mirrors.tencent.com/composer/"
    }
  ]
}

exclude的作用是排除寻找某个包,这样它就会从下一个规范仓库的镜像源中去寻找包。

  • 缺点:
    • 配置麻烦,如果出现正源有很多包都没更新的情况下,配置是个噩梦,这种情况下还是建议换源。
    • 备用镜像源也没有最新包的情况下,问题依旧,还需再另外配置备用镜像源。
  • 好处:性能更好,更安全。

解决方法四

自己搭建源,暂不开展

缺点:增加维护包的成本、搭建服务成本。

解决方法五

修改项目的composer.json,设置查找包的方式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "repositories": [
    {
      "type": "package",
      "package": {
        "name": "wppd/aliyun-log-php-sdk",
        "version": "1.0.4",
        "dist": {
          "url": "https://github.com/aliyun/aliyun-log-php-sdk/archive/refs/tags/v1.0.zip",
          "type": "zip"
        }
      }
    }	
  ]
}

或者将包下载到本地,直接引用本地路径:

1
2
3
4
5
6
{
  "repositories": [{  
    "type": "path",  
    "url": "/your_local_path/fruitcake/php-cors"
  }]
}

缺点:需要额外配置项目的composer.json以及维护包的版本。

镜像源

列一下常用的几个镜像源,请自行设置:

参考

Built with Hugo
主题 StackJimmy 设计