Passed
Push — master ( bf5af9...2729ea )
by Songda
02:00
created

PreparePlugin::getAppAuthToken()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 7
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yansongda\Pay\Plugin\Alipay;
6
7
use Closure;
8
use Yansongda\Pay\Contract\PluginInterface;
9
use Yansongda\Pay\Exception\Exception;
10
use Yansongda\Pay\Exception\InvalidConfigException;
11
use Yansongda\Pay\Logger;
12
use Yansongda\Pay\Rocket;
13
14
class PreparePlugin implements PluginInterface
15
{
16
    /**
17
     * @throws \Yansongda\Pay\Exception\ContainerException
18
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
19
     * @throws \Yansongda\Pay\Exception\InvalidConfigException
20
     */
21
    public function assembly(Rocket $rocket, Closure $next): Rocket
22
    {
23
        Logger::info('[alipay][PreparePlugin] 插件开始装载', ['rocket' => $rocket]);
24
25
        $rocket->mergePayload($this->getPayload($rocket->getParams()));
26
27
        Logger::info('[alipay][PreparePlugin] 插件装载完毕', ['rocket' => $rocket]);
28
29
        return $next($rocket);
30
    }
31
32
    /**
33
     * @throws \Yansongda\Pay\Exception\ContainerException
34
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
35
     * @throws \Yansongda\Pay\Exception\InvalidConfigException
36
     */
37
    protected function getPayload(array $params): array
38
    {
39
        return [
40
            'app_id' => get_alipay_config($params)->get('app_id', ''),
41
            'method' => '',
42
            'format' => 'JSON',
43
            'return_url' => $this->getReturnUrl($params),
44
            'charset' => 'utf-8',
45
            'sign_type' => 'RSA2',
46
            'sign' => '',
47
            'timestamp' => date('Y-m-d H:i:s'),
48
            'version' => '1.0',
49
            'notify_url' => $this->getNotifyUrl($params),
50
            'app_auth_token' => $this->getAppAuthToken($params),
51
            'app_cert_sn' => $this->getAppCertSn($params),
52
            'alipay_root_cert_sn' => $this->getAlipayRootCertSn($params),
53
            'biz_content' => [],
54
        ];
55
    }
56
57
    /**
58
     * @throws \Yansongda\Pay\Exception\ContainerException
59
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
60
     */
61
    protected function getReturnUrl(array $params): string
62
    {
63
        if (!empty($params['_return_url'])) {
64
            return $params['_return_url'];
65
        }
66
67
        return get_alipay_config($params)->get('return_url', '');
68
    }
69
70
    /**
71
     * @throws \Yansongda\Pay\Exception\ContainerException
72
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
73
     */
74
    protected function getNotifyUrl(array $params): string
75
    {
76
        if (!empty($params['_notify_url'])) {
77
            return $params['_notify_url'];
78
        }
79
80
        return get_alipay_config($params)->get('notify_url', '');
81
    }
82
83
    /**
84
     * @throws \Yansongda\Pay\Exception\ContainerException
85
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
86
     */
87
    protected function getAppAuthToken(array $params): string
88
    {
89
        if (!empty($params['_app_auth_token'])) {
90
            return $params['_app_auth_token'];
91
        }
92
93
        return get_alipay_config($params)->get('app_auth_token', '');
94
    }
95
96
    /**
97
     * @throws \Yansongda\Pay\Exception\ContainerException
98
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
99
     * @throws \Yansongda\Pay\Exception\InvalidConfigException
100
     */
101
    protected function getAppCertSn(array $params): string
102
    {
103
        $path = get_alipay_config($params)->get('app_public_cert_path');
104
105
        if (is_null($path)) {
106
            throw new InvalidConfigException(Exception::ALIPAY_CONFIG_ERROR, 'Missing Alipay Config -- [app_public_cert_path]');
107
        }
108
109
        $cert = file_get_contents($path);
110
        $ssl = openssl_x509_parse($cert);
111
112
        return $this->getCertSn($ssl['issuer'], $ssl['serialNumber']);
113
    }
114
115
    /**
116
     * @throws \Yansongda\Pay\Exception\ContainerException
117
     * @throws \Yansongda\Pay\Exception\InvalidConfigException
118
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
119
     */
120
    protected function getAlipayRootCertSn(array $params): string
121
    {
122
        $path = get_alipay_config($params)->get('alipay_root_cert_path');
123
124
        if (is_null($path)) {
125
            throw new InvalidConfigException(Exception::ALIPAY_CONFIG_ERROR, 'Missing Alipay Config -- [alipay_root_cert_path]');
126
        }
127
128
        $sn = '';
129
        $exploded = explode('-----END CERTIFICATE-----', file_get_contents($path));
130
131
        foreach ($exploded as $cert) {
132
            if (empty(trim($cert))) {
133
                continue;
134
            }
135
136
            $ssl = openssl_x509_parse($cert.'-----END CERTIFICATE-----');
137
138
            if (false === $ssl) {
139
                throw new InvalidConfigException(Exception::ALIPAY_CONFIG_ERROR, 'Invalid alipay_root_cert');
140
            }
141
142
            $detail = $this->formatCert($ssl);
143
144
            if ('sha1WithRSAEncryption' == $detail['signatureTypeLN'] || 'sha256WithRSAEncryption' == $detail['signatureTypeLN']) {
145
                $sn .= $this->getCertSn($detail['issuer'], $detail['serialNumber']).'_';
146
            }
147
        }
148
149
        return substr($sn, 0, -1);
150
    }
151
152
    protected function getCertSn(array $issuer, string $serialNumber): string
153
    {
154
        return md5(
155
            $this->array2string(array_reverse($issuer)).$serialNumber
156
        );
157
    }
158
159
    protected function array2string(array $array): string
160
    {
161
        $string = [];
162
163
        foreach ($array as $key => $value) {
164
            $string[] = $key.'='.$value;
165
        }
166
167
        return implode(',', $string);
168
    }
169
170
    protected function formatCert(array $ssl): array
171
    {
172
        if (0 === strpos($ssl['serialNumber'], '0x')) {
173
            $ssl['serialNumber'] = $this->hex2dec($ssl['serialNumberHex']);
174
        }
175
176
        return $ssl;
177
    }
178
179
    protected function hex2dec(string $hex): string
180
    {
181
        $dec = '0';
182
        $len = strlen($hex);
183
184
        for ($i = 1; $i <= $len; ++$i) {
185
            $dec = bcadd(
186
                $dec,
187
                bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i), 0), 0),
188
                0
189
            );
190
        }
191
192
        return $dec;
193
    }
194
}
195