前言

最近在使用阿里云的 OSS 服务时,发现了一些问题。
当php版本高于8.0的时候 src/OSS/SignerV1.php 中会出现 null 值错误。
issue地址
目前已解决。各位更新 2.7.1 版本即可。

问题原因

line 17-20

1
2
3
4
// Credentials information
if (strlen($credentials->getSecurityToken()) > 0) {
$request->add_header("x-oss-security-token", $credentials->getSecurityToken());
}
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?php


namespace OSS\Credentials;

use OSS\Core\OssException;

/**
* Basic implementation of the OSS Credentials that allows callers to
* pass in the OSS Access Key and OSS Secret Access Key in the constructor.
*/
class Credentials
{
private $key;
private $secret;
private $token;

/**
* Constructor a new BasicOSSCredentials object, with the specified OSS
* access key and OSS secret key
*
* @param string $key OSS access key ID
* @param string $secret OSS secret access key
* @param string $token Security token to use
*/
public function __construct($key, $secret, $token = null)
{
if (empty($key)) {
throw new OssException("access key id is empty");
}
if (empty($secret)) {
throw new OssException("access key secret is empty");
}
$this->key = trim($key);
$this->secret = trim($secret);
$this->token = $token;
}


/**
* @return string
*/
public function getAccessKeyId()
{
return $this->key;
}

/**
* @return string
*/
public function getAccessKeySecret()
{
return $this->secret;
}

/**
* @return string|null
*/
public function getSecurityToken()
{
return $this->token;
}
}

$token 是一个可选参数,当没有传入时,$token 的值是 null,所以在 SignerV1.php 中的 strlen($credentials->getSecurityToken()) 会报错。

line 25-27

1
2
3
$queryString = parse_url($request->request_url, PHP_URL_QUERY);
$query = array();
parse_str($queryString, $query);

这3行代码目的是将url中的参数解析成数组,但是当url中没有参数时,parse_url 返回的是 nullparse_str 无法解析 null,所以会报错。

解决方案

只能修改源码,将 null 值的判断加上。

line 17-20

1
2
3
4
// Credentials information
if ($credentials->getSecurityToken() !== null && strlen($credentials->getSecurityToken()) > 0) {
$request->add_header("x-oss-security-token", $credentials->getSecurityToken());
}

line 25-27

1
2
3
4
5
$queryString = parse_url($request->request_url, PHP_URL_QUERY);
$query = array();
if ($queryString !== null) {
parse_str($queryString, $query);
}

但是我个人比较好奇其他语言的源码是怎么写的,所以我去看了一下 java 的源码,发现 java 的源码中对 null 值的判断是有的。
下面是 java 对于 SecurityToken 的源码部分。

1
2
3
public String getSecurityToken() {
return securityToken;
}

1
2
3
public void setSecurityToken(String securityToken) {
this.securityToken = securityToken;
}

1
2
3
public boolean hasSecurityToken() {
return securityToken != null;
}

也就是说,在 SignerV1 中,获取 SecurityToken 的时候,会先判断 SecurityToken 是否为 null,如果不为 null 才会执行后续的操作。
php 的源码中没有对 null 值的判断,所以会报错。

总结

开猿节流的BUG