Authorizer::getCanonicalQueryString()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 8
ccs 6
cts 6
cp 1
crap 1
rs 10
1
<?php
2
3
namespace Sulao\BaiduBos;
4
5
/**
6
 * Class Authorizer
7
 *
8
 * @package Sulao\BaiduBos
9
 */
10
class Authorizer
11
{
12
    const HEADERS_TO_SIGN = [
13
        'host',
14
        'content-length',
15
        'content-type',
16
        'content-md5',
17
    ];
18
19
    const BCE_HEADER_PREFIX = 'x-bce-';
20
21
    /**
22
     * @var int
23
     */
24
    protected $expiredIn = 1800;
25
26
    /**
27
     * @var string
28
     */
29
    protected $accessKey;
30
31
    /**
32
     * @var string
33
     */
34
    protected $secretKey;
35
36
    /**
37
     * Authorizer constructor.
38
     *
39
     * @param string $accessKey
40
     * @param string $secretKey
41
     */
42 1
    public function __construct($accessKey, $secretKey)
43
    {
44 1
        $this->accessKey = $accessKey;
45 1
        $this->secretKey = $secretKey;
46
    }
47
48
    /**
49
     * @param string $method
50
     * @param string $path
51
     * @param array  $query
52
     * @param array  $headers
53
     * @param array  $options
54
     *
55
     * @return string
56
     */
57 2
    public function getAuthorization(
58
        $method,
59
        $path,
60
        array $query = [],
61
        array $headers = [],
62
        array $options = []
63
    ) {
64 2
        $canonicalURI = $this->getCanonicalURI($path);
65 2
        $canonicalQueryString = $this->getCanonicalQueryString($query);
66
67 2
        $headerToSign = $this->getHeadersToSign(
68 2
            $headers,
69 2
            isset($options['sign_headers']) ? $options['sign_headers'] : [],
70 2
            $hasSignedHeader
71 2
        );
72 2
        $canonicalHeader = $this->getCanonicalHeaders($headerToSign);
73
74 2
        $canonicalRequest = implode(
75 2
            "\n",
76 2
            [$method, $canonicalURI, $canonicalQueryString, $canonicalHeader]
77 2
        );
78
79 2
        $signedHeaders = $hasSignedHeader
80 1
            ? $this->getSignedHeaders(array_keys($headerToSign))
81 2
            : '';
82
83 2
        $expired = isset($options['expired_in'])
84 1
            ? $options['expired_in']
85 2
            : $this->expiredIn;
86 2
        $authPrefix = $this->authPrefix($expired);
87 2
        $signingKey = hash_hmac('sha256', $authPrefix, $this->secretKey);
88 2
        $signature = hash_hmac('sha256', $canonicalRequest, $signingKey);
89
90 2
        return $authPrefix . '/' . $signedHeaders . '/' . $signature;
91
    }
92
93
    /**
94
     * @param int $expiredIn
95
     *
96
     * @return string
97
     */
98 2
    protected function authPrefix($expiredIn)
99
    {
100 2
        return 'bce-auth-v1/' . $this->accessKey . '/'
101 2
            . gmdate('Y-m-d\TH:i:s\Z') . '/' . $expiredIn;
102
    }
103
104
    /**
105
     * @param string $path
106
     *
107
     * @return string
108
     */
109 2
    protected function getCanonicalURI($path)
110
    {
111 2
        $path = '/' . ltrim($path, '/');
112
113 2
        return str_replace('%2F', '/', rawurlencode($path));
114
    }
115
116
    /**
117
     * @param array     $headers
118
     * @param array     $signHeaders
119
     * @param bool|null $hasSignedHeader
120
     *
121
     * @return array
122
     */
123 2
    protected function getHeadersToSign(
124
        array $headers,
125
        array $signHeaders = [],
126
        &$hasSignedHeader = null
127
    ) {
128 2
        $signHeaders = array_map('strtolower', $signHeaders);
129 2
        $len = strlen(self::BCE_HEADER_PREFIX);
130
131 2
        $hasSignedHeader = false;
132 2
        $arr = [];
133 2
        foreach ($headers as $key => $value) {
134
            if (
135 2
                in_array(strtolower($key), self::HEADERS_TO_SIGN)
136 2
                || substr($key, 0, $len) === self::BCE_HEADER_PREFIX
137
            ) {
138 2
                $arr[$key] = $value;
139 2
            } elseif (in_array(strtolower($key), $signHeaders)) {
140 1
                $arr[$key] = $value;
141 1
                $hasSignedHeader = true;
142
            }
143
        }
144
145 2
        return $arr;
146
    }
147
148
    /**
149
     * @param array $query
150
     *
151
     * @return string
152
     */
153 2
    protected function getCanonicalQueryString(array $query)
154
    {
155 2
        $arr = array_map(function ($value, $key) {
156 2
            return rawurlencode((string)$key) . '=' . rawurlencode((string)$value);
157 2
        }, $query, array_keys($query));
158 2
        sort($arr);
159
160 2
        return implode('&', $arr);
161
    }
162
163
    /**
164
     * @param array $headers
165
     *
166
     * @return string
167
     */
168 2
    protected function getCanonicalHeaders(array $headers)
169
    {
170 2
        $arr = array_map(function ($value, $key) {
171 2
            return rawurlencode(strtolower(trim($key)))
172 2
                . ':' . rawurlencode(trim($value));
173 2
        }, $headers, array_keys($headers));
174 2
        sort($arr);
175
176 2
        return implode("\n", $arr);
177
    }
178
179
    /**
180
     * @param array $headers
181
     *
182
     * @return string
183
     */
184 1
    protected function getSignedHeaders(array $headers)
185
    {
186 1
        $headers = array_map(function ($header) {
187 1
            return rawurlencode(strtolower(trim($header)));
188 1
        }, $headers);
189 1
        sort($headers);
190
191 1
        return implode(';', $headers);
192
    }
193
}
194