Completed
Push — master ( bf6a7e...87baad )
by Songda
01:52
created

Alipay::find()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
c 0
b 0
f 0
rs 9.4285
cc 1
eloc 4
nc 1
nop 1
1
<?php
2
3
namespace Yansongda\Pay\Gateways\Alipay;
4
5
use Yansongda\Pay\Support\Config;
6
use Yansongda\Pay\Traits\HasHttpRequest;
7
use Yansongda\Pay\Contracts\GatewayInterface;
8
use Yansongda\Pay\Exceptions\GatewayException;
9
use Yansongda\Pay\Exceptions\InvalidArgumentException;
10
11
abstract class Alipay implements GatewayInterface
12
{
13
    use HasHttpRequest;
14
15
    /**
16
     * 支付宝支付网关.
17
     *
18
     * @var string
19
     */
20
    protected $gateway = 'https://openapi.alipay.com/gateway.do';
21
22
    /**
23
     * 支付宝公共参数.
24
     *
25
     * @var array
26
     */
27
    protected $config;
28
29
    /**
30
     * 用户的传参.
31
     *
32
     * @var Yansongda\Pay\Support\Config
33
     */
34
    protected $user_config;
35
36
    /**
37
     * [__construct description].
38
     *
39
     * @author yansongda <[email protected]>
40
     *
41
     * @version 2017-08-14
42
     *
43
     * @param   array      $config [description]
44
     */
45
    public function __construct(array $config)
46
    {
47
        $this->user_config = new Config($config);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Yansongda\Pay\Support\Config($config) of type object<Yansongda\Pay\Support\Config> is incompatible with the declared type object<Yansongda\Pay\Gat...gda\Pay\Support\Config> of property $user_config.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
48
49
        if (is_null($this->user_config->get('app_id'))) {
50
            throw new InvalidArgumentException("Missing Config -- [app_id]");
51
        }
52
53
        $this->config = [
54
            'app_id' => $this->user_config->get('app_id'),
55
            'method' => '',
56
            'format' => 'JSON',
57
            'charset' => 'utf-8',
58
            'sign_type' => 'RSA2',
59
            'version' => '1.0',
60
            'return_url' => $this->user_config->get('return_url', ''),
61
            'notify_url' => $this->user_config->get('notify_url', ''),
62
            'timestamp' => date('Y-m-d H:i:s'),
63
            'sign' => '',
64
            'biz_content' => '',
65
        ];
66
    }
67
68
69
    /**
70
     * 对外接口 - 支付.
71
     *
72
     * @author yansongda <[email protected]>
73
     *
74
     * @version 2017-08-15
75
     *
76
     * @param   array      $config_biz [description]
77
     *
78
     * @return  string                 [description]
79
     */
80 View Code Duplication
    public function pay(array $config_biz = [])
81
    {
82
        $config_biz['product_code'] = $this->getPayProductCode();
83
84
        $this->config['method'] = $this->getPayMethod();
85
        $this->config['biz_content'] = json_encode($config_biz, JSON_UNESCAPED_UNICODE);
86
        $this->config['sign'] = $this->getSign();
87
88
        return $this->buildPayHtml();
89
    }
90
91
    /**
92
     * 对外接口 - 退款.
93
     *
94
     * @author yansongda <[email protected]>
95
     *
96
     * @version 2017-08-15
97
     *
98
     * @param   mixed      $config_biz [description]
99
     *
100
     * @return  array|boolean          [description]
101
     */
102
    public function refund($config_biz, $refund_amount = null)
103
    {
104
        if (!is_array($config_biz)) {
105
            $config_biz = [
106
                'out_trade_no' => $config_biz,
107
                'refund_amount' => $refund_amount,
108
            ];
109
        }
110
111
        return $this->getResult($config_biz, 'alipay.trade.refund');
112
    }
113
114
    /**
115
     * 对外接口 - 关闭.
116
     *
117
     * @author yansongda <[email protected]>
118
     *
119
     * @version 2017-08-15
120
     *
121
     * @param   array|string $config_biz [description]
122
     *
123
     * @return  array|boolean            [description]
124
     */
125
    public function close($config_biz)
126
    {
127
        if (!is_array($config_biz)) {
128
            $config_biz = [
129
                'out_trade_no' => $config_biz,
130
            ];
131
        }
132
133
        return $this->getResult($config_biz, 'alipay.trade.close');
134
    }
135
136
    /**
137
     * 对外接口 - 订单查询
138
     * @author yansongda <[email protected]>
139
     * 
140
     * @version 2017-08-19
141
     * 
142
     * @param   string     $out_trade_no 商家订单号
143
     * 
144
     * @return  array|boolean            [description]
145
     */
146
    public function find($out_trade_no = '')
147
    {
148
        $config_biz = [
149
            'out_trade_no' => $out_trade_no,
150
        ];
151
        
152
        return $this->getResult($config_biz, 'alipay.trade.query');
153
    }
154
155
    /**
156
     * 对外接口 - 验证.
157
     *
158
     * @author yansongda <[email protected]>
159
     *
160
     * @version 2017-08-11
161
     *
162
     * @param   array      $data 待签名数组
163
     * @param   string     $sign 签名字符串-支付宝服务器发送过来的原始串
164
     * @param   bool       $sync 是否同步验证
165
     *
166
     * @return  array|boolean    [description]
167
     */
168
    public function verify($data, $sign = null, $sync = false)
169
    {
170
        if (is_null($this->user_config->get('ali_public_key'))) {
171
            throw new InvalidArgumentException("Missing Config -- [ali_public_key]");
172
        }
173
174
        $sign = is_null($sign) ? $data['sign'] : $sign;
175
176
        $res = "-----BEGIN PUBLIC KEY-----\n" .
177
                wordwrap($this->user_config->get('ali_public_key'), 64, "\n", true) .
178
                "\n-----END PUBLIC KEY-----";
179
180
        $toVerify = $sync ? json_encode($data, JSON_UNESCAPED_UNICODE) : $this->getSignContent($data, true);
181
        
182
        return openssl_verify($toVerify, base64_decode($sign), $res, OPENSSL_ALGO_SHA256) === 1 ? $data : false;
183
    }
184
185
    /**
186
     * [getMethod description].
187
     *
188
     * @author yansongda <[email protected]>
189
     *
190
     * @version 2017-08-10
191
     *
192
     * @return  string     [description]
193
     */
194
    abstract protected function getPayMethod();
195
196
    /**
197
     * [getProductCode description].
198
     *
199
     * @author yansongda <[email protected]>
200
     *
201
     * @version 2017-08-10
202
     *
203
     * @return  string     [description]
204
     */
205
    abstract protected function getPayProductCode();
206
207
    /**
208
     * [buildHtmlPay description]
209
     *
210
     * @author yansongda <[email protected]>
211
     *
212
     * @version 2017-08-11
213
     *
214
     * @return  string     [description]
215
     */
216
    protected function buildPayHtml()
217
    {
218
        $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->gateway . "?charset=utf-8' method='POST'>";
219
        while (list ($key, $val) = each($this->config)) {
220
            $val = str_replace("'", "&apos;", $val);
221
            $sHtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
222
        }
223
        $sHtml .= "<input type='submit' value='ok' style='display:none;''></form>";
224
        $sHtml .= "<script>document.forms['alipaysubmit'].submit();</script>";
225
        
226
        return $sHtml;
227
    }
228
229
    /**
230
     * get alipay api result.
231
     *
232
     * @author yansongda <[email protected]>
233
     *
234
     * @version 2017-08-12
235
     *
236
     * @param   array      $config_biz [description]
237
     * @param   string     $method     [description]
238
     *
239
     * @return  array|boolean          [description]
240
     */
241
    protected function getResult($config_biz, $method)
242
    {
243
        $this->config['biz_content'] = json_encode($config_biz, JSON_UNESCAPED_UNICODE);
244
        $this->config['method'] = $method;
245
        $this->config['sign'] = $this->getSign();
246
247
        $method = str_replace('.', '_', $method) . '_response';
248
        
249
        $data = json_decode($this->post($this->gateway, $this->config), true);
250
251
        if (!isset($data[$method]['code']) || $data[$method]['code'] !== '10000') {
252
            throw new GatewayException(
253
                'get result error:' . $data[$method]['msg'] . ' - ' . $data[$method]['sub_msg'],
254
                $data[$method]['code'],
255
                $data);
256
        }
257
258
        return $this->verify($data[$method], $data['sign'], true);
259
    }
260
261
    /**
262
     * 签名.
263
     *
264
     * @author yansongda <[email protected]>
265
     *
266
     * @version 2017-08-10
267
     *
268
     * @return  string     [description]
269
     */
270
    protected function getSign()
271
    {
272
        if (is_null($this->user_config->get('private_key'))) {
273
            throw new InvalidArgumentException("Missing Config -- [private_key]");
274
        }
275
276
        $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
277
                wordwrap($this->user_config->get('private_key'), 64, "\n", true) .
278
                "\n-----END RSA PRIVATE KEY-----";
279
280
        openssl_sign($this->getSignContent($this->config), $sign, $res, OPENSSL_ALGO_SHA256);
281
282
        return base64_encode($sign);
283
    }
284
285
    /**
286
     * 待签名数组.
287
     *
288
     * @author yansongda <[email protected]>
289
     *
290
     * @version 2017-08-11
291
     *
292
     * @param   array      $toBeSigned [description]
293
     * @param   boolean    $verify     是否异步同时验证签名
294
     *
295
     * @return  string                 [description]
296
     */
297
    protected function getSignContent(array $toBeSigned, $verify = false)
298
    {
299
        ksort($toBeSigned);
300
301
        $stringToBeSigned = "";
302
        foreach ($toBeSigned as $k => $v) {
303
            if ($verify && $k != 'sign' && $k != 'sign_type') {
304
                $stringToBeSigned .= $k . "=" . $v . "&";
305
            }
306
            if (!$verify && $v !== '' && !is_null($v) && $k != 'sign' && "@" != substr($v, 0, 1)) {
307
                $stringToBeSigned .= $k . "=" . $v . "&";
308
            }
309
        }
310
        $stringToBeSigned = substr($stringToBeSigned, 0, -1);
311
        unset ($k, $v);
312
313
        return $stringToBeSigned;
314
    }
315
316
}
317