Passed
Push — master ( 535bd5...f77f61 )
by wannanbigpig
03:11
created

Helpers::sign()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 4.0047

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 17
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 28
ccs 14
cts 15
cp 0.9333
crap 4.0047
rs 9.7
1
<?php
2
/*
3
 * This file is part of the wannanbigpig/alipay-sdk-php.
4
 *
5
 * (c) wannanbigpig <[email protected]>
6
 *
7
 * This source file is subject to the MIT license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace EasyAlipay\Kernel\Traits;
12
13
use EasyAlipay\Kernel\Exceptions\InvalidSignException;
14
use WannanBigPig\Supports\Exceptions\InvalidArgumentException;
15
16
/**
17
 * Class Helpers
18
 *
19
 * @author   liuml  <[email protected]>
20
 * @DateTime 2019-07-18  17:00
21
 */
22
trait Helpers
23
{
24
    /**
25
     * generateSign.
26
     *
27
     * @param        $data
28
     * @param string $signType
29
     *
30
     * @return string
31
     *
32
     * @throws \WannanBigPig\Supports\Exceptions\InvalidArgumentException
33
     */
34 14
    public function generateSign($data, $signType = 'RSA2')
35
    {
36 14
        return $this->sign($this->getSignContent($data), $signType);
37
    }
38
39
    /**
40
     * getSignContent.
41
     *
42
     * @param $params
43
     *
44
     * @return string
45
     */
46 16
    public function getSignContent($params)
47
    {
48 16
        ksort($params);
49
50 16
        $stringToBeSigned = "";
51 16
        $i = 0;
52 16
        foreach ($params as $k => $v) {
53 16
            if (false === $this->checkEmpty($v) && "@" !== substr($v, 0, 1)) {
54 16
                if ($i === 0) {
55 16
                    $stringToBeSigned .= "$k"."="."$v";
56
                } else {
57 14
                    $stringToBeSigned .= "&"."$k"."="."$v";
58
                }
59 16
                $i++;
60
            }
61
        }
62
63 16
        unset($k, $v);
64
65 16
        return $stringToBeSigned;
66
    }
67
68
    /**
69
     * This method does URLEncode for values.
70
     *
71
     * @param $params
72
     *
73
     * @return string
74
     */
75 14
    public function getSignContentUrlencode($params)
76
    {
77 14
        ksort($params);
78
79 14
        $stringToBeSigned = "";
80 14
        $i = 0;
81 14
        foreach ($params as $k => $v) {
82 4
            if (false === $this->checkEmpty($v) && "@" !== substr($v, 0, 1)) {
83 4
                if ($i === 0) {
84 4
                    $stringToBeSigned .= "$k"."=".urlencode($v);
85
                } else {
86 4
                    $stringToBeSigned .= "&"."$k"."=".urlencode($v);
87
                }
88 4
                $i++;
89
            }
90
        }
91
92 14
        unset($k, $v);
93
94 14
        return $stringToBeSigned;
95
    }
96
97
    /**
98
     * sign.
99
     *
100
     * @param        $data
101
     * @param string $signType
102
     *
103
     * @return string
104
     *
105
     * @throws \WannanBigPig\Supports\Exceptions\InvalidArgumentException
106
     */
107 16
    protected function sign($data, $signType = "RSA2")
108
    {
109 16
        $rsaPrivateKeyFilePath = $this->app['config']->get('private_key_path');
110 16
        if ($this->checkEmpty($rsaPrivateKeyFilePath)) {
111 2
            $priKey = $this->app['config']['private_key'];
112
            $priKey = "-----BEGIN RSA PRIVATE KEY-----\n".
113 2
                wordwrap($priKey, 64, "\n", true).
114 2
                "\n-----END RSA PRIVATE KEY-----";
115
        } else {
116 14
            $priKey = file_get_contents($rsaPrivateKeyFilePath);
117
        }
118
119 16
        $res = openssl_get_privatekey($priKey);
120
121 16
        if ($res === false) {
122
            throw new InvalidArgumentException('Invalid private_key configuration');
123
        }
124
125 16
        if ("RSA2" === $signType) {
126 16
            openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
127
        } else {
128 2
            openssl_sign($data, $sign, $res);
129
        }
130
131
        // Release resources
132 16
        openssl_free_key($res);
133
134 16
        return base64_encode($sign);
135
    }
136
137
    /**
138
     * checkEmpty.
139
     *
140
     * @param $value
141
     *
142
     * @return bool
143
     */
144 20
    protected function checkEmpty($value)
145
    {
146 20
        if ($value === null) {
147 14
            return true;
148
        }
149
150 18
        if (is_string($value)) {
151 18
            if (trim($value) === "") {
152 18
                return true;
153
            }
154
        } elseif (is_array($value)) {
155
            if (count($value) < 1) {
156
                return true;
157
            }
158
        }
159
160
161 18
        return false;
162
    }
163
164
    /**
165
     * parserSignSource.
166
     *
167
     * @param array       $response
168
     * @param string|null $apiMethod
169
     *
170
     * @return array|mixed
171
     */
172
    public function parserSignSource(array $response, string $apiMethod = null)
173
    {
174
        $response_suffix = '_response';
175
        $error_respones = 'error_response';
176
        $apiMethod = $this->app['config']['api_method'] ?? $apiMethod;
177
        $rootNodeName = str_replace(".", "_", $apiMethod).$response_suffix;
178
179
        if (isset($response[$rootNodeName])) {
180
            return $response[$rootNodeName];
181
        } elseif (isset($response[$error_respones])) {
182
            return $response[$error_respones];
183
        } else {
184
            return $response;
185
        }
186
    }
187
188
    /**
189
     * verify sign.
190
     *
191
     * @param string $data
192
     * @param        $sign
193
     * @param string $signType
194
     *
195
     * @return bool
196
     *
197
     * @throws \WannanBigPig\Supports\Exceptions\InvalidArgumentException
198
     */
199 2
    public function verify(string $data, $sign, $signType = 'RSA2')
200
    {
201 2
        $alipayPublicKeyPath = $this->app['config']->get('alipay_public_Key_path');
202 2
        if ($this->checkEmpty($alipayPublicKeyPath)) {
203
            $pubKey = $this->app['config']->get('alipay_public_Key');
204
            $pubKey = "-----BEGIN PUBLIC KEY-----\n".
205
                wordwrap($pubKey, 64, "\n", true).
206
                "\n-----END PUBLIC KEY-----";
207
        } else {
208
            // Read public key file
209 2
            $pubKey = file_get_contents($alipayPublicKeyPath);
210
        }
211
212
        // Convert to openssl format key
213 2
        $res = openssl_get_publickey($pubKey);
214
215 2
        if ($res === false) {
216
            throw new InvalidArgumentException('Invalid alipay_public_Key configuration');
217
        }
218
219
        // Call openssl built-in method checksum, return bool value
220 2
        if ("RSA2" === $signType) {
221 2
            $result = (openssl_verify($data, base64_decode($sign, true), $res, OPENSSL_ALGO_SHA256) === 1);
222
        } else {
223 2
            $result = (openssl_verify($data, base64_decode($sign, true), $res) === 1);
224
        }
225
226
        // Release resources
227 2
        openssl_free_key($res);
228
229 2
        return $result;
230
    }
231
232
    /**
233
     * checkResponseSign.
234
     *
235
     * @param             $content
236
     * @param string|null $sign
237
     *
238
     * @return bool
239
     *
240
     * @throws \EasyAlipay\Kernel\Exceptions\InvalidSignException
241
     * @throws \WannanBigPig\Supports\Exceptions\InvalidArgumentException
242
     */
243 2
    public function checkResponseSign($content, string $sign = null)
244
    {
245 2
        if (!is_null($sign)) {
246 2
            $result = $this->verify(
247 2
                $content,
248 2
                $sign,
249 2
                $this->app['config']->get('sign_type', 'RSA2')
250
            );
251
        } else {
252
            throw new InvalidSignException('check sign Fail! The reason : sign data is Empty', 0, $content);
253
        }
254
255 2
        if (!$result) {
256
            throw new InvalidSignException(sprintf(
257
                '"%s" method responds to parameter validation signature error',
258
                $this->app['config']['api_method']
259
            ));
260
        }
261
262 2
        return $result;
263
    }
264
}
265